cleanup: drop debug prints — auth fallback verified working

This commit is contained in:
wasrusgen 2026-05-12 21:56:53 +03:00
parent 8bf18c00b0
commit e42178e876
2 changed files with 1 additions and 30 deletions

View File

@ -15,43 +15,27 @@ def verify_init_data(init_data: str, bot_token: str, max_age_sec: int = 86400) -
Спецификация: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app Спецификация: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app
""" """
import sys
if not init_data: if not init_data:
print("[AUTH] empty init_data", flush=True, file=sys.stderr)
return None return None
parsed = dict(parse_qsl(init_data, keep_blank_values=True)) parsed = dict(parse_qsl(init_data, keep_blank_values=True))
received_hash = parsed.pop("hash", None) received_hash = parsed.pop("hash", None)
if not received_hash: if not received_hash:
print(f"[AUTH] no hash in initData. keys={list(parsed.keys())}", flush=True, file=sys.stderr)
return None return None
# data_check_string: ключ=значение, отсортированы алфавитно, разделитель \n # data_check_string: ключ=значение, отсортированы алфавитно, разделитель \n
data_check_string = "\n".join(f"{k}={parsed[k]}" for k in sorted(parsed)) data_check_string = "\n".join(f"{k}={parsed[k]}" for k in sorted(parsed))
# Trim token to handle accidental whitespace in env
token_clean = bot_token.strip()
# secret_key = HMAC-SHA-256(key="WebAppData", data=BOT_TOKEN) # secret_key = HMAC-SHA-256(key="WebAppData", data=BOT_TOKEN)
secret_key = hmac.new(b"WebAppData", token_clean.encode(), hashlib.sha256).digest() secret_key = hmac.new(b"WebAppData", bot_token.strip().encode(), hashlib.sha256).digest()
expected_hash = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256).hexdigest() expected_hash = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected_hash, received_hash): if not hmac.compare_digest(expected_hash, received_hash):
print(
f"[AUTH] HASH MISMATCH\n"
f" token_len={len(bot_token)} clean_len={len(token_clean)} "
f"head={token_clean[:6]}... tail=...{token_clean[-6:]}\n"
f" data_check_string={data_check_string!r}\n"
f" received_hash={received_hash}\n"
f" expected_hash={expected_hash}",
flush=True, file=sys.stderr,
)
return None return None
# Свежесть подписи (24 часа по умолчанию) # Свежесть подписи (24 часа по умолчанию)
auth_date = int(parsed.get("auth_date", "0")) auth_date = int(parsed.get("auth_date", "0"))
if time.time() - auth_date > max_age_sec: if time.time() - auth_date > max_age_sec:
print(f"[AUTH] auth_date too old: {auth_date}, now={time.time()}", flush=True, file=sys.stderr)
return None return None
print(f"[AUTH] OK auth_date={auth_date}", flush=True, file=sys.stderr)
user = None user = None
if "user" in parsed: if "user" in parsed:

View File

@ -422,22 +422,17 @@ def api_catalog_preview_ai(cats: str = "fridge", tiers: str = ""):
# ================================================================= # =================================================================
def _handle_me(body: dict[str, Any]) -> dict[str, Any]: def _handle_me(body: dict[str, Any]) -> dict[str, Any]:
import sys
print(f"[ME] entry: body keys={list(body.keys())} role_in_body={body.get('role')!r}", flush=True, file=sys.stderr)
cfg = get_config() cfg = get_config()
init_data = body.get("initData") or "" init_data = body.get("initData") or ""
auth = verify_init_data(init_data, cfg.bot_token) auth = verify_init_data(init_data, cfg.bot_token)
print(f"[ME] auth result: ok={bool(auth)} user_present={bool(auth and auth.get('user'))}", flush=True, file=sys.stderr)
# Fallback для Telegram Desktop side-panel — initData может приходить пустым. # Fallback для Telegram Desktop side-panel — initData может приходить пустым.
# Доверяем initDataUnsafe.user (НЕпроверенным данным) — только для UI-режима. # Доверяем initDataUnsafe.user (НЕпроверенным данным) — только для UI-режима.
# Все endpoint-ы, выполняющие действия, продолжают требовать подписанный initData. # Все endpoint-ы, выполняющие действия, продолжают требовать подписанный initData.
if not auth or not auth.get("user"): if not auth or not auth.get("user"):
unsafe = body.get("initDataUnsafe") or {} unsafe = body.get("initDataUnsafe") or {}
print(f"[ME] fallback inspect: initDataUnsafe type={type(unsafe).__name__} keys={list(unsafe.keys()) if isinstance(unsafe, dict) else 'N/A'} value={str(unsafe)[:300]}", flush=True, file=sys.stderr)
unsafe_user = unsafe.get("user") if isinstance(unsafe, dict) else None unsafe_user = unsafe.get("user") if isinstance(unsafe, dict) else None
if unsafe_user and unsafe_user.get("id"): if unsafe_user and unsafe_user.get("id"):
print(f"[ME] FALLBACK: using initDataUnsafe.user id={unsafe_user.get('id')}", flush=True, file=sys.stderr)
auth = { auth = {
"user": unsafe_user, "user": unsafe_user,
"auth_date": int(time.time()), "auth_date": int(time.time()),
@ -445,7 +440,6 @@ def _handle_me(body: dict[str, Any]) -> dict[str, Any]:
"_unsafe": True, "_unsafe": True,
} }
else: else:
print(f"[ME] fallback FAILED: unsafe_user={unsafe_user}", flush=True, file=sys.stderr)
return {"error": "invalid_init_data"} return {"error": "invalid_init_data"}
tg_user = auth["user"] tg_user = auth["user"]
@ -456,13 +450,6 @@ def _handle_me(body: dict[str, Any]) -> dict[str, Any]:
# Берём roles из словаря если они уже распарсены (после grant_role), # Берём roles из словаря если они уже распарсены (после grant_role),
# иначе fallback на парсинг сырой CSV-колонки # иначе fallback на парсинг сырой CSV-колонки
roles = user.get("roles") or sheets.parse_roles(user.get("role", "")) roles = user.get("roles") or sheets.parse_roles(user.get("role", ""))
import sys
print(
f"[ME] tg_id={tg_id} admin_id={cfg.admin_tg_id} "
f"explicit_role={explicit_role!r} user.role={user.get('role')!r} "
f"roles={roles}",
flush=True, file=sys.stderr,
)
# Staff (замерщик / сборщик) — отдельный кабинет, доступен только тем у кого роль выдана # Staff (замерщик / сборщик) — отдельный кабинет, доступен только тем у кого роль выдана
if explicit_role == "staff": if explicit_role == "staff":