Skip to content

feat: add otp on the post sending process#181

Draft
drendog wants to merge 1 commit intoUNICT-DMI:mainfrom
drendog:feature/totp
Draft

feat: add otp on the post sending process#181
drendog wants to merge 1 commit intoUNICT-DMI:mainfrom
drendog:feature/totp

Conversation

@drendog
Copy link
Copy Markdown
Contributor

@drendog drendog commented Feb 8, 2026

Prerequisites

  • I have read and understood the contributing guide.
  • The commit message follows the conventional commits guidelines.
  • Tested the changes locally with a real Telegram bot.
  • Introduced tests for the changes have been added (for bug fixes / features).
  • Docs have been added/updated (for bug fixes / features).
  • I have updated the CHANGELOG.md file with an overview of the changes made.

Description

Adds totp verification on the post sending process, to avoid attackers sending post from a stolen account (like the possible recent incident) and other worst-case scenarios.

Does this PR introduce a breaking change?

  • Yes
  • No

(If yes) What are the changes that might break existing applications?

Description of the changes that might break existing applications.

Python version you are using

3.14.2

Other information

@drendog drendog marked this pull request as draft February 8, 2026 10:54
warn_expiration_days: 60
mute_default_duration_days: 7
totp: true
mandatory_totp: true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not set it as mandatory by default

@staticmethod
def is_enabled() -> bool:
"""Whether TOTP is enabled (either mandatory or optional)"""
return bool(Config.post_get("totp", False)) or bool(Config.post_get("mandatory_totp", False))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bool conversion is handled by the Config class

@staticmethod
def is_required() -> bool:
"""Whether TOTP is mandatory for all users"""
return bool(Config.post_get("mandatory_totp", False))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bool conversion is handled by the Config class

@staticmethod
def is_optional() -> bool:
"""Whether TOTP is optional (users can opt-in)"""
return bool(Config.post_get("totp", False)) and not bool(Config.post_get("mandatory_totp", False))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bool conversion is handled by the Config class

@staticmethod
def create_secret(user_id: int) -> str:
"""Generates a new TOTP secret, stores it in the database, and returns it"""
secret = pyotp.random_base32()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be safe, it could be worth checking whether the secret already exists, and if that's the case, either leave it or override it.

secret = TotpManager.create_secret(user_id)
provisioning_uri = TotpManager.get_provisioning_uri(user_id, secret)
qr_buffer = TotpManager.generate_qr_image(provisioning_uri)
return secret, qr_buffer
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth returning the uri as well

next state of the conversation (TOTP_SETUP)
"""
_, qr_buffer = TotpManager.setup_user_totp(info.user_id)
await info.bot.send_photo(chat_id=info.chat_id, photo=qr_buffer, caption=read_md("totp_setup"))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would assume that most people use Telegram from their phones. On older models, it may be awkward to scan the qr code on the screen. Adding the uri to the caption of the qr code as a clickable link would solve the issue

Comment on lines +62 to +69
elif action == "totp":
if TotpManager.has_totp(info.user_id):
text = "TOTP è già attivo sul tuo account"
else:
_, qr_buffer = TotpManager.setup_user_totp(info.user_id)
await info.bot.send_photo(chat_id=info.chat_id, photo=qr_buffer, caption=read_md("totp_setup"))
text = "TOTP attivato! D'ora in poi ti verrà chiesto il codice quando invii uno spot"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should also be the option to deactivate the totp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants