Skip to content

Fix/magic link bot auth#24

Merged
Fl1riX merged 9 commits into
mainfrom
fix/magic-link-bot-auth
May 29, 2026
Merged

Fix/magic link bot auth#24
Fl1riX merged 9 commits into
mainfrom
fix/magic-link-bot-auth

Conversation

@Fl1riX
Copy link
Copy Markdown
Owner

@Fl1riX Fl1riX commented May 27, 2026

Summary by Sourcery

Обеспечена безопасность генерации magic-ссылок для Telegram с помощью общего секрета бота и улучшено логирование, связанное с созданием ссылок.

New Features:

  • Требование наличия валидного заголовка X-Bot-Secret для запросов на генерацию Telegram magic-ссылок с использованием настраиваемого значения BOT_SECRET.
  • Введение функции проверки секрета бота с постоянным временем выполнения (constant-time) в TgLinkService и повторное использование её в клиенте Telegram при обращении к API.

Bug Fixes:

  • Предотвращение генерации magic-ссылок неавторизованными ботами за счёт обязательного контроля доступа, основанного на секрете.

Enhancements:

  • Улучшение сообщений логирования для привязки Telegram-аккаунта и сохранения magic-токена для повышения наблюдаемости.
  • Уточнение пользовательских сообщений об ошибках, когда Telegram-аккаунт уже привязан к платформе.

Build:

  • Добавление зависимостей для CLI и вспомогательных утилит (например, commitizen и связанных библиотек) в requirements.txt.
Original summary in English

Summary by Sourcery

Secure Telegram magic link generation behind a shared bot secret and improve logging around link creation.

New Features:

  • Require a valid X-Bot-Secret header for Telegram magic link generation requests using a configurable BOT_SECRET value.
  • Introduce a constant-time bot secret verification helper in TgLinkService and reuse it in the Telegram client when calling the API.

Bug Fixes:

  • Prevent unauthorized bots from generating magic links by enforcing secret-based access control.

Enhancements:

  • Improve logging messages for Telegram account linking and magic token persistence to aid observability.
  • Clarify user-facing error messages when a Telegram account is already linked to the platform.

Build:

  • Add CLI and helper dependencies (e.g. commitizen and related libraries) to requirements.txt.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 27, 2026

Руководство для ревьюера

Добавляет HMAC-проверку общего секрета бота для генерации Telegram magic-link, прокидывает секрет бота через конфиг и Telegram‑клиент, ужесточает контроль доступа к API генерации magic-link и обновляет зависимости для поддержки инструментов работы с коммитами.

Диаграмма последовательности генерации Telegram magic-link с проверкой X-Bot-Secret

sequenceDiagram
    actor TgUser
    participant TgBot as TgClient
    participant Api as create_telegram_magic_link
    participant TgService as TgLinkService
    participant Config as BOT_SECRET
    participant DB as AsyncSession

    TgUser->>TgBot: generate_magic_token(tg_id)
    TgBot->>TgBot: BOT_SECRET
    TgBot->>Api: GET /auth/telegram/generate-link/{tg_id}\nX-Bot-Secret: BOT_SECRET

    Api->>Api: request.headers.get(X-Bot-Secret)
    Api->>TgService: verify_bot_secret_key(bot_secret_header)
    TgService->>Config: BOT_SECRET
    TgService-->>Api: bool

    Api->>TgService: check_telegram_connection(telegram_id, db)
    TgService->>DB: select(User)
    TgService-->>Api: User | None

    Api->>TgService: save_link_token(token, expires_at, db, telegram_id)
    TgService->>DB: insert(MagicToken)
    TgService-->>Api: None

    Api-->>TgBot: { token }
    TgBot-->>TgUser: magic token status
Loading

Изменения на уровне файлов

Изменение Детали Файлы
Ввести проверку заголовка X-Bot-Secret для эндпоинта генерации Telegram magic-link и улучшить логирование/сообщения.
  • Использовать исключение NoAccess для отклонения запросов без корректного заголовка X-Bot-Secret.
  • Считать X-Bot-Secret из заголовков запроса и проверять его через TgLinkService перед продолжением обработки.
  • Уточнить сообщения логов для входящих запросов, проверок заголовков, существующей привязки Telegram и сохранения токена.
  • Сделать сообщение ошибки NotCorrect более информативным для уже привязанных аккаунтов Telegram.
src/presentation/api/v1/auth/tg_link.py
Добавить безопасную логику проверки секрета бота с использованием HMAC и предоставить её через TgLinkService.
  • Импортировать BOT_SECRET из конфигурации в tg_link_service.
  • Добавить статический метод verify_bot_secret_key, который использует hmac.compare_digest для устойчивого к атакам по времени сравнения.
  • Логировать предупреждение при невалидных попытках использования секрета бота и выбрасывать runtime‑ошибку, если BOT_SECRET не сконфигурирован.
src/domain/services/tg_link_service.py
Прокинуть секрет бота из конфигурации окружения в Telegram‑клиент и прикреплять его к запросам генерации magic‑токенов.
  • Добавить BOT_SECRET в конфигурацию приложения, загружаемую из переменных окружения.
  • Импортировать BOT_SECRET в сервис tg_client.
  • Прикреплять заголовок X-Bot-Secret с BOT_SECRET к HTTP‑запросам, вызывающим API генерации magic-link.
src/config.py
src/domain/services/tg_client.py
Расширить зависимости Python, добавив инструменты для работы с коммитами и их рантайм‑зависимости.
  • Добавить commitizen и связанные CLI/терминальные вспомогательные библиотеки, такие как argcomplete, decli, prompt_toolkit, questionary, termcolor, tomlkit, wcwidth и Jinja2 в requirements.
requirements.txt

Подсказки и команды

Взаимодействие с Sourcery

  • Запустить новое ревью: Оставьте комментарий @sourcery-ai review в pull request.
  • Продолжить обсуждение: Отвечайте напрямую на комментарии ревью от Sourcery.
  • Создать задачу GitHub из комментария ревью: Попросите Sourcery создать задачу из комментария ревью, ответив на него. Также можно ответить на комментарий ревью с @sourcery-ai issue, чтобы создать задачу на его основе.
  • Сгенерировать заголовок pull request: Напишите @sourcery-ai в заголовке pull request, чтобы в любой момент сгенерировать заголовок. Также можно оставить комментарий @sourcery-ai title в pull request, чтобы (пере)сгенерировать заголовок в любой момент.
  • Сгенерировать краткое описание pull request: Напишите @sourcery-ai summary в теле pull request в том месте, где вы хотите получить итоговое описание. Также можно оставить комментарий @sourcery-ai summary в pull request, чтобы (пере)сгенерировать summary в любой момент.
  • Сгенерировать руководство для ревьюера: Оставьте комментарий @sourcery-ai guide в pull request, чтобы (пере)сгенерировать руководство для ревьюера в любой момент.
  • Разрешить все комментарии Sourcery: Оставьте комментарий @sourcery-ai resolve в pull request, чтобы пометить все комментарии Sourcery как решённые. Полезно, если вы уже обработали все комментарии и больше не хотите их видеть.
  • Отклонить все ревью Sourcery: Оставьте комментарий @sourcery-ai dismiss в pull request, чтобы отклонить все существующие ревью Sourcery. Особенно полезно, если вы хотите начать с нуля с новым ревью — не забудьте затем оставить комментарий @sourcery-ai review, чтобы запустить новое ревью!

Настройка работы

Зайдите в свою панель управления, чтобы:

  • Включать или отключать функции ревью, такие как автоматически сгенерированное Sourcery краткое описание pull request, руководство для ревьюера и другие.
  • Изменить язык ревью.
  • Добавлять, удалять или редактировать пользовательские инструкции для ревью.
  • Настроить другие параметры ревью.

Получение помощи

Original review guide in English

Reviewer's Guide

Adds HMAC-based verification of a shared bot secret for Telegram magic link generation, wires the bot secret through config and the Telegram client, tightens access control on the magic link API, and updates dependencies to support commit tooling.

Sequence diagram for Telegram magic link generation with X-Bot-Secret verification

sequenceDiagram
    actor TgUser
    participant TgBot as TgClient
    participant Api as create_telegram_magic_link
    participant TgService as TgLinkService
    participant Config as BOT_SECRET
    participant DB as AsyncSession

    TgUser->>TgBot: generate_magic_token(tg_id)
    TgBot->>TgBot: BOT_SECRET
    TgBot->>Api: GET /auth/telegram/generate-link/{tg_id}\nX-Bot-Secret: BOT_SECRET

    Api->>Api: request.headers.get(X-Bot-Secret)
    Api->>TgService: verify_bot_secret_key(bot_secret_header)
    TgService->>Config: BOT_SECRET
    TgService-->>Api: bool

    Api->>TgService: check_telegram_connection(telegram_id, db)
    TgService->>DB: select(User)
    TgService-->>Api: User | None

    Api->>TgService: save_link_token(token, expires_at, db, telegram_id)
    TgService->>DB: insert(MagicToken)
    TgService-->>Api: None

    Api-->>TgBot: { token }
    TgBot-->>TgUser: magic token status
Loading

File-Level Changes

Change Details Files
Enforce X-Bot-Secret header validation for Telegram magic link generation endpoint and improve logging/messages.
  • Add NoAccess exception usage to deny requests without a valid X-Bot-Secret header.
  • Read X-Bot-Secret from request headers and verify it via TgLinkService before proceeding.
  • Refine log messages around incoming requests, header checks, existing Telegram linkage, and token persistence.
  • Adjust NotCorrect error message to be more descriptive for already-linked Telegram accounts.
src/presentation/api/v1/auth/tg_link.py
Introduce secure bot secret verification logic using HMAC and expose it via TgLinkService.
  • Import BOT_SECRET from configuration into tg_link_service.
  • Add verify_bot_secret_key static method that uses hmac.compare_digest for timing-attack resistant comparison.
  • Log a warning on invalid bot secret attempts and raise a runtime error when BOT_SECRET is not configured.
src/domain/services/tg_link_service.py
Wire bot secret from environment configuration through to the Telegram client and attach it to magic token generation requests.
  • Add BOT_SECRET to application configuration loaded from environment variables.
  • Import BOT_SECRET into tg_client service.
  • Attach X-Bot-Secret header with BOT_SECRET to HTTP requests calling the magic link generation API.
src/config.py
src/domain/services/tg_client.py
Expand Python dependencies to include commit tooling and its runtime requirements.
  • Add commitizen and related CLI/terminal helper libraries such as argcomplete, decli, prompt_toolkit, questionary, termcolor, tomlkit, wcwidth, and Jinja2 to requirements.
requirements.txt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Привет! Я нашёл 2 проблемы и оставил несколько общих замечаний:

  • Обращение к BOT_SECRET через os.environ["BOT_SECRET"] вызовет KeyError на этапе импорта, если переменная отсутствует, что помешает приложению стартовать; имеет смысл использовать os.getenv с явной валидацией при запуске, чтобы ошибки конфигурации обрабатывались контролируемым образом.
  • Логика валидации X-Bot-Secret сейчас дублируется между API-слоем и сервисом (извлечение заголовка + verify_bot_secret_key); стоит инкапсулировать это в FastAPI dependency или middleware, чтобы все маршруты, требующие bot secret, использовали одну и ту же проверку и обработку ошибок.
  • Некоторые новые сообщения логгера довольно подробные и используют logger.info для потенциально высокочастотных или низкоуровневых проверок (например, наличие заголовка и сравнение ключей); стоит понизить часть таких логов до debug, чтобы избежать шума в логах в продакшене.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Accessing BOT_SECRET via os.environ["BOT_SECRET"] will raise a KeyError at import time if the variable is missing, which prevents the app from starting; consider using os.getenv with explicit validation during startup so configuration errors are handled in a controlled way.
- The X-Bot-Secret validation logic is now duplicated between the API layer and the service (header extraction + verify_bot_secret_key); consider encapsulating this into a FastAPI dependency or middleware so all routes that require the bot secret can share the same check and error handling.
- Some of the new log messages are quite verbose and use logger.info for what might be high-frequency or low-level checks (e.g., header presence and key comparison); consider downgrading some of these to debug to avoid noisy logs in production.

## Individual Comments

### Comment 1
<location path="src/domain/services/tg_link_service.py" line_range="13-14" />
<code_context>

 class TgLinkService:
+    @staticmethod
+    def verify_bot_secret_key(bot_secret_header: str):
+        """  
+        Сравниваем секретный ключ с полученным ключем в заголовке. 
+        Устранена возможность timig атаки.
</code_context>
<issue_to_address>
**nitpick (typo):** Docstring and log message contain typos that may hinder future maintenance/searchability

In `verify_bot_secret_key`, please fix typos in the docstring/log messages: `timig``timing`, `ключем``ключом`, `Не верный``Неверный` to keep security-related text clear and searchable.

Suggested implementation:

```python
    def verify_bot_secret_key(bot_secret_header: str):
        """
        Сравниваем секретный ключ с полученным ключом в заголовке.
        Устранена возможность timing-атаки.
        """

```

```python
        if not result:
            logger.warning("Неверный ключ в X-Bot-Secret. Возможна попытка атаки!")

```
</issue_to_address>

### Comment 2
<location path="src/presentation/api/v1/auth/tg_link.py" line_range="39-44" />
<code_context>
+    logger.info("Сравнение ключей...")
+    verify_key = TgLinkService.verify_bot_secret_key(bot_secret_header)
+    
+    if not verify_key:
+        logger.info("Предоставленый ключ не совпадает с секретным ключем")
+        raise NoAccess("Недостаточно прав для доступа к этому ресурсу")
+    
</code_context>
<issue_to_address>
**nitpick (typo):** Typographical issues in the log message for invalid bot secret

Please correct the Russian typos in the log message: `Предоставленый``Предоставленный`, `ключем``ключом` to keep logs clear and consistent.

```suggestion
    logger.info("Сравнение ключей...")
    verify_key = TgLinkService.verify_bot_secret_key(bot_secret_header)

    if not verify_key:
        logger.info("Предоставленный ключ не совпадает с секретным ключом")
        raise NoAccess("Недостаточно прав для доступа к этому ресурсу")
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Помогите мне стать полезнее! Пожалуйста, нажимайте 👍 или 👎 под каждым комментарием — я использую эту обратную связь, чтобы улучшать следующие обзоры.
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • Accessing BOT_SECRET via os.environ["BOT_SECRET"] will raise a KeyError at import time if the variable is missing, which prevents the app from starting; consider using os.getenv with explicit validation during startup so configuration errors are handled in a controlled way.
  • The X-Bot-Secret validation logic is now duplicated between the API layer and the service (header extraction + verify_bot_secret_key); consider encapsulating this into a FastAPI dependency or middleware so all routes that require the bot secret can share the same check and error handling.
  • Some of the new log messages are quite verbose and use logger.info for what might be high-frequency or low-level checks (e.g., header presence and key comparison); consider downgrading some of these to debug to avoid noisy logs in production.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Accessing BOT_SECRET via os.environ["BOT_SECRET"] will raise a KeyError at import time if the variable is missing, which prevents the app from starting; consider using os.getenv with explicit validation during startup so configuration errors are handled in a controlled way.
- The X-Bot-Secret validation logic is now duplicated between the API layer and the service (header extraction + verify_bot_secret_key); consider encapsulating this into a FastAPI dependency or middleware so all routes that require the bot secret can share the same check and error handling.
- Some of the new log messages are quite verbose and use logger.info for what might be high-frequency or low-level checks (e.g., header presence and key comparison); consider downgrading some of these to debug to avoid noisy logs in production.

## Individual Comments

### Comment 1
<location path="src/domain/services/tg_link_service.py" line_range="13-14" />
<code_context>

 class TgLinkService:
+    @staticmethod
+    def verify_bot_secret_key(bot_secret_header: str):
+        """  
+        Сравниваем секретный ключ с полученным ключем в заголовке. 
+        Устранена возможность timig атаки.
</code_context>
<issue_to_address>
**nitpick (typo):** Docstring and log message contain typos that may hinder future maintenance/searchability

In `verify_bot_secret_key`, please fix typos in the docstring/log messages: `timig``timing`, `ключем``ключом`, `Не верный``Неверный` to keep security-related text clear and searchable.

Suggested implementation:

```python
    def verify_bot_secret_key(bot_secret_header: str):
        """
        Сравниваем секретный ключ с полученным ключом в заголовке.
        Устранена возможность timing-атаки.
        """

```

```python
        if not result:
            logger.warning("Неверный ключ в X-Bot-Secret. Возможна попытка атаки!")

```
</issue_to_address>

### Comment 2
<location path="src/presentation/api/v1/auth/tg_link.py" line_range="39-44" />
<code_context>
+    logger.info("Сравнение ключей...")
+    verify_key = TgLinkService.verify_bot_secret_key(bot_secret_header)
+    
+    if not verify_key:
+        logger.info("Предоставленый ключ не совпадает с секретным ключем")
+        raise NoAccess("Недостаточно прав для доступа к этому ресурсу")
+    
</code_context>
<issue_to_address>
**nitpick (typo):** Typographical issues in the log message for invalid bot secret

Please correct the Russian typos in the log message: `Предоставленый``Предоставленный`, `ключем``ключом` to keep logs clear and consistent.

```suggestion
    logger.info("Сравнение ключей...")
    verify_key = TgLinkService.verify_bot_secret_key(bot_secret_header)

    if not verify_key:
        logger.info("Предоставленный ключ не совпадает с секретным ключом")
        raise NoAccess("Недостаточно прав для доступа к этому ресурсу")
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/domain/services/tg_link_service.py Outdated
Comment thread src/presentation/api/v1/auth/tg_link.py
Squ1reX and others added 2 commits May 29, 2026 16:18
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 26639560946

Coverage decreased (-0.2%) to 28.072%

Details

  • Coverage decreased (-0.2%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 54 coverage regressions across 3 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

54 previously-covered lines in 3 files lost coverage.

File Lines Losing Coverage Coverage
presentation/api/v1/auth/tg_link.py 20 0.0%
domain/services/tg_client.py 19 0.0%
domain/services/tg_link_service.py 15 76.12%

Coverage Stats

Coverage Status
Relevant Lines: 1172
Covered Lines: 329
Line Coverage: 28.07%
Coverage Strength: 0.56 hits per line

💛 - Coveralls

@coveralls
Copy link
Copy Markdown

coveralls commented May 29, 2026

Coverage Report for CI Build 26639796309

Coverage decreased (-0.2%) to 28.072%

Details

  • Coverage decreased (-0.2%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 54 coverage regressions across 3 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

54 previously-covered lines in 3 files lost coverage.

File Lines Losing Coverage Coverage
presentation/api/v1/auth/tg_link.py 20 0.0%
domain/services/tg_client.py 19 0.0%
domain/services/tg_link_service.py 15 76.12%

Coverage Stats

Coverage Status
Relevant Lines: 1172
Covered Lines: 329
Line Coverage: 28.07%
Coverage Strength: 0.56 hits per line

💛 - Coveralls

@Fl1riX Fl1riX merged commit 3346714 into main May 29, 2026
4 checks passed
@Fl1riX Fl1riX deleted the fix/magic-link-bot-auth branch May 29, 2026 13:24
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