2 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7377fb61e5 |
feat(tradein/support): веб-чат поддержки поверх Telegram support-моста
Сайт закрыт Caddy basic_auth, тред привязывается к X-Authenticated-User (нет анонимов). Новые web_support_threads/web_support_messages (миграция 187) — отдельно от tg_support_* (186): у веб-клиента нет Telegram chat_id, смешение identity-схем в одной таблице потребовало бы NULLABLE chat_id/username и XOR CHECK-ограничений без реальной выгоды (обоснование в самой миграции). API (app/api/v1/support.py, /api/v1/trade-in/support/*): POST /messages — отправка (sendMessage-зеркало в топик, "[С САЙТА] user: ...") GET /messages — polling своего треда (?since=id) GET /unread — счётчик непрочитанного POST /read — отметить прочитанным Тред резолвится ИСКЛЮЧИТЕЛЬНО по username — нет параметра, которым можно адресовать чужой тред (структурная защита от IDOR, не только access-check). bridge.py: _handle_group_reply получил ветку резолва reply в web-тред (после существующего tg-резолва, без изменения Telegram-пути) — оператор отвечает одинаково, вне зависимости от канала клиента. Rate-limit: новый SlidingWindowLimiter (ratelimit.py) — 12 msg/60s per user, жёстче общего RateLimitMiddleware (общий бот-токен, флуд одного клиента иначе бьёт по доставке всем). Security: этот процесс (app/main.py) теперь тоже зовёт Telegram Bot API напрямую (раньше — только изолированный tgbot_main.py) — реплицированы обе защиты токена: httpx-INFO подавлен, include_local_variables=False + redact_telegram_bot_token в sentry before_send. Бот не сконфигурирован (пустой TELEGRAM_BOT_TOKEN/chat_id) → 503, не 500. |
||
|
|
b579fa4ced |
feat(tradein/tgbot): Telegram support-мост @MERAsupport_bot
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m4s
Клиент пишет боту в личку → воркер зеркалит сообщение через copyMessage в топик супергруппы-форума → оператор отвечает реплаем на зеркало → бот доставляет ответ клиенту. Полный лог переписки в Postgres. Отдельный контейнер на long-polling, а не webhook в tradein-backend: не нужно пробивать дырку в auth-middleware (_PUBLIC_PATHS, #2213) и маршрут в Caddy, нулевая внешняя поверхность, падение бота не задевает API. Без aiogram — httpx уже в зависимостях, нужны только getUpdates/copyMessage. Маршрутизация ответа — по topic_message_id: message_id в Telegram уникален в пределах чата сквозь все топики, а все зеркала лежат в одном support-чате, поэтому спутать адресата нельзя. Реплай на шапку/на ответ другого оператора не резолвится (у direction='out' topic_message_id IS NULL) → тихий игнор. Безопасность (найдено ревью, воспроизведено эмпирически): - токен Telegram живёт в PATH URL, поэтому sanitize_url его не режет; утекал в GlitchTip через locals стек-фреймов (include_local_variables по умолчанию True) и через span data HttpxIntegration. Закрыто include_local_variables=False + regex-редактор в before_send (обе формы: /bot<id>:<secret> и голая <id>:<secret>), поверх существующего PII-scrub. - httpx-логгер печатает полный URL на INFO → боевой токен уходил бы в docker logs каждые 30с. Приглушён до WARNING. Надёжность: - kill-switch при пустом токене — idle-блокировка, не exit(0): при restart: unless-stopped выход с любым кодом даёт рестарт-луп. unless-stopped выбран сознательно — только он гарантирует автозапуск после ребута VPS. - stop_grace_period: 120s — дефолтные 10с убивали бы контейнер раньше, чем докрутится long-poll (30с) и отработает drain (100с). - сбой SQL теперь ловится отдельно и делает rollback перед сдвигом offset: иначе сессия в failed-transaction не давала сохранить offset, апдейт переигрывался и зеркалился в топик по кругу. 152-ФЗ: переписка — ПДн, ON DELETE CASCADE по chat_id, удаление клиента одним DELETE. Ретенция — follow-up. Бот не включается автоматически: TELEGRAM_* задаются в runtime-env на VPS, без них воркер штатно висит в idle. Порядок — в DEPLOY.md. Тесты: 51 passed (маршрутизация обоих направлений, дедуп, 403→is_blocked, throttle-окно шапки, redaction токена во всех формах event). |