mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
92 lines
2.6 KiB
Python
92 lines
2.6 KiB
Python
"""Utilities for validating Telegram WebApp initialization data."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import hmac
|
|
import json
|
|
import time
|
|
from typing import Any, Dict
|
|
from urllib.parse import parse_qsl
|
|
|
|
|
|
class TelegramWebAppAuthError(Exception):
|
|
"""Raised when Telegram WebApp init data fails validation."""
|
|
|
|
|
|
def parse_webapp_init_data(
|
|
init_data: str,
|
|
bot_token: str,
|
|
*,
|
|
max_age_seconds: int = 86400,
|
|
) -> Dict[str, Any]:
|
|
"""Validate and parse Telegram WebApp init data.
|
|
|
|
Args:
|
|
init_data: Raw init data string provided by Telegram WebApp.
|
|
bot_token: Bot token used to verify the signature.
|
|
max_age_seconds: Maximum allowed age for the payload. Defaults to 24 hours.
|
|
|
|
Returns:
|
|
Parsed init data as a dictionary.
|
|
|
|
Raises:
|
|
TelegramWebAppAuthError: If validation fails.
|
|
"""
|
|
|
|
if not init_data:
|
|
raise TelegramWebAppAuthError("Missing init data")
|
|
|
|
if not bot_token:
|
|
raise TelegramWebAppAuthError("Bot token is not configured")
|
|
|
|
parsed_pairs = parse_qsl(init_data, strict_parsing=True, keep_blank_values=True)
|
|
data: Dict[str, Any] = {key: value for key, value in parsed_pairs}
|
|
|
|
received_hash = data.pop("hash", None)
|
|
if not received_hash:
|
|
raise TelegramWebAppAuthError("Missing init data signature")
|
|
|
|
data_check_string = "\n".join(
|
|
f"{key}={value}" for key, value in sorted(data.items())
|
|
)
|
|
|
|
secret_key = hmac.new(
|
|
key=b"WebAppData",
|
|
msg=bot_token.encode("utf-8"),
|
|
digestmod=hashlib.sha256,
|
|
).digest()
|
|
|
|
computed_hash = hmac.new(
|
|
key=secret_key,
|
|
msg=data_check_string.encode("utf-8"),
|
|
digestmod=hashlib.sha256,
|
|
).hexdigest()
|
|
|
|
if not hmac.compare_digest(computed_hash, received_hash):
|
|
raise TelegramWebAppAuthError("Invalid init data signature")
|
|
|
|
auth_date_raw = data.get("auth_date")
|
|
if auth_date_raw is not None:
|
|
try:
|
|
auth_date = int(auth_date_raw)
|
|
except (TypeError, ValueError):
|
|
raise TelegramWebAppAuthError("Invalid auth_date value") from None
|
|
|
|
if max_age_seconds and auth_date:
|
|
current_ts = int(time.time())
|
|
if current_ts - auth_date > max_age_seconds:
|
|
raise TelegramWebAppAuthError("Init data is too old")
|
|
|
|
data["auth_date"] = auth_date
|
|
|
|
user_payload = data.get("user")
|
|
if user_payload is not None:
|
|
try:
|
|
data["user"] = json.loads(user_payload)
|
|
except json.JSONDecodeError as error:
|
|
raise TelegramWebAppAuthError("Invalid user payload") from error
|
|
|
|
return data
|
|
|