How to develop a Telegram bot in Python that will generate complex passwords directly in the messenger?

To come up with a reliable and memorable password, you can combine several words into a sequence resembling a plot. And then — dilute with special characters. The algorithm is simple, but it can be automated — write a Telegram bot to generate passwords. In the text we tell you how to do it.

Author: Olivia Bell
10/17/22
Requirements for the work of the bot
Before we start writing code, let's define the rules by which the bot should work.

The password length should be from 2 to 8 words. So we will complicate the task of the attacker: it is much more difficult to pick up a bunch of words than one word.
There can be separators between words in the form of numbers and special characters. This will increase entropy and make password selection more difficult. A delimited password may look like this:

unmovable8ENCRUST=macho.

Additionally, special characters can be used in the password at the beginning (prefixes) and at the end (suffixes) of the word, which will also help increase the complexity of the selection.

The number of words, separators, prefixes and suffixes must be configured by the user. To do this, he needs an interface in the form of a message with settings buttons.
User settings should be saved even after restarting the server with the bot. Redis is suitable as a database.

What you will need to develop a bot

Before you start, you need to prepare the development environment, install the necessary libraries and programs, namely:

Python — from version 3.9 and higher,
aiogram is an asynchronous framework for working with the Telegram Bot API,
Redis — fast key-value storage,
redis-py — client for working with Redis,
XKCD-password-generator is a library for generating passwords,
pydantic is a library for validating data and forming application settings.
The most important thing is the repository on GitHub. You need to import it into your working environment and configure it.

How to set up a bot

Let's launch the bot locally. At this stage, we can do without Redis, but it is important to keep in mind that user settings will not be saved between restarts.

If you use the PyCharm development environment, it will be as easy as possible to launch the bot. After cloning the repository, switch to the article-tweaks branch (git checkout article-tweaks) and create a new startup configuration (Run Configuration). And then set the parameters:

BOT_TOKEN — specify the bot token, you can get it from @BotFather.
STORAGE_MODE — select memory.
WORDS__WORDFILE — specify the path to the file with the set of words. It is part of the repository, so you do not need to download it separately.
It should work out as in the screenshot:


After that, run the created configuration. You will see the following text in the console:

INFO:aiogram.dispatcher.dispatcher:Start polling
If you are not using PyCharm, then the startup process is somewhat different. Create a bot virtual environment (python3 -m venv bot) and install dependencies (pip install -r requirements.txt ), and then — run the bot with the following command:

BOT_TOKEN=key from BotFather STORAGE_MODE=memory WORDS__WORDFILE=/path/to/words.txt python -m bot
Now try sending the /start command to private messages with the bot. If you received a text greeting in response, the bot is working.

When entering a character / you should see a list of commands. Try to call them up and explore the different configurations. The following presets are supported by default:

/generate_weak -- two random words without any additional characters.
/generate_normal — three random words, each of which can randomly consist of all uppercase or all lowercase letters, numbers are used as separators.
/generate_strong is the same as in the previous case, but there are four words, and special characters are possible as separators, in addition to numbers.

When you click on the command, the bot immediately sends the generated password.
There is also a command /settings — it displays a message with the settings, and /generate — sends the generated password taking into account the new configuration:


Deploy the bot to the server
Everything is ready, but there is a problem: the bot is running on the computer. This is inconvenient if you want to ensure the round-the-clock operation of the bot. After all, then you need to maintain the smooth operation of the computer and a constant connection to the Internet.

The optimal solution is to upload the bot to a cloud server with flexible core performance. This way you can ensure stable operation and limit resource consumption so as not to overpay.

To get started, register in the control panel and create a new server in the Cloud Platform section. Then — configure it.


The bot is suitable for Ubuntu 22.04 LTS OS, 2 virtual cores with a minimum limit of 10% of processor time, 2 GB of RAM, as well as 10 GB on a network drive (basic HDD).

Taking into account the allocated IP address, this configuration will be released at about 28 ₽/day. If desired, you can do without a routed IP, since the Telegram bot can receive events by polling (polling), even while behind the NAT.

After connecting to the server via SSH, the bot needs to be moved. To do this, follow these steps:

1. Open the server console and update the system using the command:
apt update && apt upgrade -y
2. Create a separate user for our bot and add him to the sudoers group:
Perform further actions on behalf of the created user.
3. Install Redis and attach it to systemd using the convenient instruction from DigitalOcean. Steps 4 and 5 can be skipped.
4. Clone the repository and switch to the desired branch:
5. Configure the virtual environment:
python3 -m venv venv && source /venv/bin/activate && pip install -r requirements.txt
6. Create a systemd service file at the path /etc/systemd/system/passgenbot.service with the following contents:

[Unit]
Description=Telegram Password Generator Bot
Requires=redis.service
After=network.target redis.service

[Service]
Type=simple
WorkingDirectory=/home/bot/passgenbot
ExecStart=/home/bot/passgenbot/venv/bin/python -m bot
User=bot
Group=bot
EnvironmentFile=/home/bot/passgenbot/.env
KillMode=process
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

7. Pay attention to the EnvironmentFile directive. Create this file and put the necessary environment variables there:
8. Make sure that Redis is running (systemctl status redis) and enable the bot with the addition of autorun:

sudo systemctl enable passgenbot --now
Ready!

Programming custom presets
The capabilities of the bot can be personalized for yourself at any time. If there are not enough presets, add new ones or change existing ones. It is quite simple to do this.

The XKCD class is responsible for generating passwords according to the preset presets. Under the hood, our bot looks like this:

# bot/pwdgen.py

from random import choice
from xkcdpass import xkcd_password

class XKCD:
# The entire list of separators, separate digits, separate special characters
delimiters_numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
delimiters_full = ["!", "$", "%", "^", "&", "*", "-", "_", "+", "=", ":", "|", "~", "?", "/", ".", ";"] + delimiters_numbers

def __init__(self, filename: str):
# Loading the dictionary into memory
self.wordlist = xkcd_password.generate_wordlist(
wordfile=filename, valid_chars="[a-z]",
min_length=4, max_length=10,
)

def weak(self):
# Weak password: 2 words without undressing
return xkcd_password.generate_xkcdpassword(
self.wordlist, numwords=2,
delimiter="", )

def normal(self):
# Average password: 3 words, delimiter
# as a random digit
return xkcd_password.generate_xkcdpassword(
self.wordlist, numwords=3, case="random", random_delimiters=True,
valid_delimiters=self.delimiters_numbers
)

def strong(self):
# Strong password: 4 words and a large selection of delimiters
return xkcd_password.generate_xkcdpassword(
self.wordlist, numwords=4, case="random", random_delimiters=True,
valid_delimiters=self.delimiters_full
)

def custom(self, count: int, separators: bool, prefixes: bool):
# Arbitrary password:
# complexity depends on user settings
pwd = xkcd_password.generate_xkcdpassword(
self.wordlist, numwords=count, case="random",
delimiter="", random_delimiters=separators,
valid_delimiters=self.delimiters_full
)
if prefixes == separators:
return pwd
elif separators and not prefixes:
return pwd[1:-1]
elif prefixes and not separators:
return f"{choice(self.delimiters_full)}{pwd}{choice(self.delimiters_full)}"
To add a new preset, it is enough to copy an existing one, change its name and configure the parameters of the generate_xkcdpassword method for yourself.

And the last step is to add a function to the commands handler to call your preset. This can be done by analogy with existing presets.

# bot/handlers/commands.py

from aiogram import types, Dispatcher
from aiogram.utils.markdown import hcode
from bot.pwdgen import XKCD

async def cmd_generate_weak(message: types.Message):
# calling the weak preset
pwd: XKCD = message.bot.get("pwd")
await message.answer(hcode(pwd.weak()))

async def cmd_generate_normal(message: types.Message):
# calling the normal preset
pwd: XKCD = message.bot.get("pwd")
await message.answer(hcode(pwd.normal()))

async def cmd_generate_strong(message: types.Message):
# calling the strong preset
pwd: XKCD = message.bot.get("pwd")
await message.answer(hcode(pwd.strong()))

# here you can add your own function to call the preset

# registering commands
def register_commands(dp: Dispatcher):
# the handler calls the weak preset by the generate_weak command
dp.register_message_handler(cmd_generate_weak, commands="generate_weak")

# the handler calls the preset normal by the generate_normal command
dp.register_message_handler(cmd_generate_normal, commands="generate_normal")

# the handler calls the strong preset by the generate_strong command
dp.register_message_handler(cmd_generate_strong, commands="generate_strong")

# here you can add your team
What can I add