diff --git a/backend/telegram.py b/backend/telegram.py index 0633462..b20e0c8 100644 --- a/backend/telegram.py +++ b/backend/telegram.py @@ -11,9 +11,21 @@ from backend import config, db logger = logging.getLogger(__name__) +# Suppress httpx/httpcore transport-level logging to prevent BOT_TOKEN URL leakage. +# httpx logs request URLs (which embed the token) at DEBUG/INFO level depending on version. +logging.getLogger("httpx").setLevel(logging.WARNING) +logging.getLogger("httpcore").setLevel(logging.WARNING) + _TELEGRAM_API = "https://api.telegram.org/bot{token}/{method}" +def _mask_token(token: str) -> str: + """Return a safe representation of the bot token for logging.""" + if not token or len(token) < 4: + return "***REDACTED***" + return f"***{token[-4:]}" + + async def validate_bot_token() -> bool: """Validate BOT_TOKEN by calling getMe. Logs ERROR if invalid. Never raises.""" url = _TELEGRAM_API.format(token=config.BOT_TOKEN, method="getMe") @@ -29,7 +41,13 @@ async def validate_bot_token() -> bool: ) return False except Exception as exc: - logger.error("BOT_TOKEN validation failed (network): %s", exc) + # Do not log `exc` directly — it may contain the API URL with the token + # embedded (httpx includes request URL in some exception types/versions). + logger.error( + "BOT_TOKEN validation failed (network error): %s — token ends with %s", + type(exc).__name__, + _mask_token(config.BOT_TOKEN), + ) return False