From 72c7d386090836eef88cb9464dea305b33adcd6b Mon Sep 17 00:00:00 2001 From: gitadmin Date: Sun, 2 Aug 2026 15:41:37 +0300 Subject: [PATCH] [ZILANT] debug - failing secret code --- tg_mainbot.py | 110 +++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/tg_mainbot.py b/tg_mainbot.py index cf6d015..a0f2e10 100644 --- a/tg_mainbot.py +++ b/tg_mainbot.py @@ -2,7 +2,6 @@ import os import logging import time import errno -import asyncio from dotenv import load_dotenv import telebot from telebot import apihelper @@ -15,13 +14,15 @@ import requests from io import BytesIO from flask import Flask, request from formatter import get_post_text, get_event_text -from telegram_relay import configure_telebot_api, get_relay_url +from telegram_relay import configure_telebot_api, get_relay_url, bot_api_method_url # Создаем Flask app на верхнем уровне для экспорта app = Flask(__name__) -# Загружаем переменные окружения из файла .env -load_dotenv() +# Загружаем .env рядом с этим файлом (не зависим от cwd gunicorn) +_ENV_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env") +load_dotenv(_ENV_PATH) +load_dotenv() # и из cwd на всякий случай # Получаем данные из переменных окружения RESPONDER_BOT_TOKEN = os.getenv('RESPONDER_BOT_TOKEN') @@ -1437,22 +1438,58 @@ def handle_callback(call): def setup_webhook(): """ - Настройка вебхука через ретранслятор — как в retransbot/testunit/echobot.py: - python-telegram-bot Bot.set_webhook(url=..., secret_token=...). - PTB передаёт параметры form-urlencoded (httpx data=), и relay их корректно - пробрасывает в Telegram вместе с secret_token. + Регистрация webhook через internal_relay. + + Важно: relay перехватывает setWebhook и уносит secret_token в Telegram через + extra_params. Параметры нужно слать как application/x-www-form-urlencoded + (так делает echobot/PTB и так разбирает relay после фикса 0.1.1). """ logger.info("starting setup_webhook") - last_error = None + if not WEBHOOK_SECRET: + raise RuntimeError( + "WEBHOOK_SECRET не задан — без него Telegram не будет присылать " + "X-Telegram-Bot-Api-Secret-Token" + ) + if not WEBHOOK_URL: + raise RuntimeError("WEBHOOK_URL не задан") + api_url = bot_api_method_url(RESPONDER_BOT_TOKEN, "setWebhook") + # Все значения — строки (form-urlencoded), как ожидает parse_qs на relay + form = { + "url": WEBHOOK_URL, + "secret_token": WEBHOOK_SECRET, + "max_connections": "40", + } + logger.info( + f"setWebhook через relay: delivery_url={WEBHOOK_URL}, " + f"secret_len={len(WEBHOOK_SECRET)}, relay={get_relay_url()}" + ) + + last_error = None for attempt in range(1, 6): try: - asyncio.run(_setup_webhook_ptb()) + resp = requests.post( + api_url, + data=form, + timeout=60, + ) + try: + data = resp.json() + except Exception: + data = {"ok": False, "description": (resp.text or "")[:500]} + logger.info(f"setWebhook ответ HTTP {resp.status_code}: {data}") + + desc = str(data.get("description", "")) if isinstance(data, dict) else "" + if resp.status_code == 429 or "retry after" in desc.lower(): + raise RuntimeError(desc or f"HTTP {resp.status_code}") + if not (isinstance(data, dict) and data.get("ok")): + raise RuntimeError(f"setWebhook failed: HTTP {resp.status_code} {data}") + logger.info( f"Вебхук установлен через ретранслятор {get_relay_url()}: " f"локальная доставка {WEBHOOK_URL}" ) - logger.info(f"Секретный токен: {'установлен' if WEBHOOK_SECRET else 'не установлен'}") + logger.info(f"Секретный токен: установлен (len={len(WEBHOOK_SECRET)})") logger.info(f"Прослушивание порта: {WEBHOOK_PORT}") logger.info(f"Путь вебхука: {WEBHOOK_PATH}") log_event("system", "system", message=f"Вебхук установлен на {WEBHOOK_URL}") @@ -1474,37 +1511,6 @@ def setup_webhook(): raise RuntimeError(error_msg) from last_error -async def _setup_webhook_ptb(): - """Регистрация webhook через PTB — тот же стек, что у проверенного echobot.""" - from telegram import Bot - from telegram.request import HTTPXRequest - from telegram_relay import get_ptb_base_urls - - base_url, base_file_url = get_ptb_base_urls() - request_kw = HTTPXRequest( - connect_timeout=30.0, - read_timeout=60.0, - write_timeout=60.0, - pool_timeout=10.0, - ) - tg_bot = Bot( - token=RESPONDER_BOT_TOKEN, - base_url=base_url, - base_file_url=base_file_url, - request=request_kw, - ) - try: - ok = await tg_bot.set_webhook( - url=WEBHOOK_URL, - secret_token=WEBHOOK_SECRET, - max_connections=40, - ) - if not ok: - raise RuntimeError("set_webhook returned False") - finally: - await tg_bot.shutdown() - - def _webhook_retry_after(exc): """Извлекает секунды ожидания из 429 / 'retry after N', иначе None.""" text = str(exc) @@ -1517,20 +1523,34 @@ def _webhook_retry_after(exc): return 2 +def _read_telegram_secret_header(): + """Читает секрет из заголовка (Flask headers и сырой WSGI environ).""" + return ( + request.headers.get("X-Telegram-Bot-Api-Secret-Token") + or request.environ.get("HTTP_X_TELEGRAM_BOT_API_SECRET_TOKEN") + ) + + # Используем путь из WEBHOOK_URL @app.route(WEBHOOK_PATH, methods=['POST']) def webhook(): logger.info("starting webhook") - received_secret = request.headers.get("X-Telegram-Bot-Api-Secret-Token") + received_secret = _read_telegram_secret_header() if received_secret != WEBHOOK_SECRET: + related = [ + k for k in request.headers.keys() + if "secret" in k.lower() or "telegram" in k.lower() or k.lower().startswith("x-") + ] if not received_secret: logger.warning( - "Секретный токен отсутствует в заголовке X-Telegram-Bot-Api-Secret-Token" + "Секретный токен отсутствует в заголовке X-Telegram-Bot-Api-Secret-Token; " + f"IP={request.remote_addr}; related_headers={related}" ) else: logger.warning( "Секретный токен не совпадает " - f"(получен len={len(received_secret)}, ожидается len={len(WEBHOOK_SECRET or '')})" + f"(получен len={len(received_secret)}, ожидается len={len(WEBHOOK_SECRET or '')}); " + f"related_headers={related}" ) log_event("security", "system", message="Попытка доступа с неверным секретным токеном") return "Unauthorized", 401