feat(bot): доступ по QR-приглашениям, раздел «Участники», отзыв доступа

- AccessService: одноразовые приглашения (128 бит, в БД только sha256, TTL 24 ч),
  атомарный захват приглашения (условный UPDATE — из двух сканов одного QR проходит один),
  антиперебор (> 5 неудач в час — молчание), отзыв (черновик и FSM удаляются), повторное приглашение
- ADMIN_IDS заводятся в БД при старте; дальше — только по приглашению
- AccessMiddleware: участники из БД (+ last_seen раз в 5 мин), новичкам — только /start <токен>
- «👥 Участники» для админов: список, QR (segno) + ссылка, отзыв с подтверждением
- один ответ на неверный/истёкший/использованный токен — без подсказок

Refs #25

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 19:03:50 +03:00
co-authored by Claude Opus 5.5
parent 4e5930b4c0
commit 219bebd5a2
16 changed files with 655 additions and 44 deletions
+16
View File
@@ -24,6 +24,7 @@ class MenuTexts(_Strict):
class StartTexts(_Strict):
welcome: str
no_access: str
invite_rejected: str
class HelpTexts(_Strict):
@@ -39,11 +40,26 @@ class SectionTexts(_Strict):
cancelled: str
class MembersTexts(_Strict):
title: str
line: str
never: str
invite: str
revoke: str
confirm: str
confirm_yes: str
confirm_no: str
revoked: str
not_revoked: str
invite_caption: str
class Texts(_Strict):
menu: MenuTexts
start: StartTexts
help: HelpTexts
section: SectionTexts
members: MembersTexts
def load_texts(config_dir: Path) -> Texts: