Files
Agro-365-bot/venv/lib/python3.12/site-packages/aiogram/utils/web_app_signature.py
2025-09-01 19:12:16 +05:00

71 lines
2.3 KiB
Python

import base64
from operator import itemgetter
from urllib.parse import parse_qsl
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.exceptions import InvalidSignature
from .web_app import parse_webapp_init_data, WebAppInitData
PRODUCTION_PUBLIC_KEY = bytes.fromhex(
"e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d"
)
TEST_PUBLIC_KEY = bytes.fromhex("40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec")
def check_webapp_signature(
bot_id: int, init_data: str, public_key_bytes: bytes = PRODUCTION_PUBLIC_KEY
) -> bool:
"""
Check incoming WebApp init data signature without bot token using only bot id.
Source: https://core.telegram.org/bots/webapps#validating-data-for-third-party-use
:param bot_id: Bot ID
:param init_data: WebApp init data
:param public_key: Public key
:return: True if signature is valid, False otherwise
"""
try:
parsed_data = dict(parse_qsl(init_data, strict_parsing=True))
except ValueError:
return False
signature_b64 = parsed_data.pop("signature", None)
if not signature_b64:
return False
parsed_data.pop("hash", None)
data_check_string = f"{bot_id}:WebAppData\n" + "\n".join(
f"{k}={v}" for k, v in sorted(parsed_data.items(), key=itemgetter(0))
)
message = data_check_string.encode()
padding = "=" * (-len(signature_b64) % 4)
signature = base64.urlsafe_b64decode(signature_b64 + padding)
public_key = Ed25519PublicKey.from_public_bytes(public_key_bytes)
try:
public_key.verify(signature, message)
return True
except InvalidSignature:
return False
def safe_check_webapp_init_data_from_signature(
bot_id: int, init_data: str, public_key_bytes: bytes = PRODUCTION_PUBLIC_KEY
) -> WebAppInitData:
"""
Validate raw WebApp init data using only bot id and return it as WebAppInitData object
:param bot_id: bot id
:param init_data: data from frontend to be parsed and validated
:param public_key_bytes: public key
:return: WebAppInitData object
"""
if check_webapp_signature(bot_id, init_data, public_key_bytes):
return parse_webapp_init_data(init_data)
raise ValueError("Invalid init data signature")