"""Webhook-Signatur-Prüfung für WhatsApp und Telegram.""" import hashlib import hmac import os from typing import Any from src.queue.handler import QueueHandler def verify_whatsapp_signature( payload: bytes, signature: str, app_secret: str | None = None ) -> bool: """Verifiziert die WhatsApp X-Hub-Signature-256. Vergleicht die übergebene Signatur mit dem berechneten HMAC-SHA256-Wert des Payloads und des App-Secrets. Nutzt timing-sicheren Vergleich. Args: payload: Der rohe Webhook-Payload als Bytes. signature: Die X-Hub-Signature-256 Signatur aus dem Header. app_secret: Das WhatsApp App Secret (optional, Fallback auf ENV). Returns: True wenn die Signatur gültig ist, False sonst. """ secret = app_secret or os.environ.get("WHATSAPP_APP_SECRET", "") if not secret: return False expected = hmac.new( secret.encode("utf-8"), payload, hashlib.sha256 ).hexdigest() expected_with_prefix = f"sha256={expected}" return hmac.compare_digest(expected_with_prefix, signature) def verify_telegram_signature( payload: bytes, hash_val: str, token: str | None = None ) -> bool: """Verifiziert den Telegram Bot Webhook Signature Hash. Telegram sendet ein 'hash'-Feld im Bot Webhook Payload. Dessen SHA256 HMAC mit dem Bot-Token als Key muss mit dem empfangenen hash-Wert übereinstimmen. Args: payload: Der rohe Webhook-Payload als Bytes (JSON). hash_val: Das 'hash'-Feld aus dem Telegram Bot Webhook. token: Das Telegram Bot Token (optional, Fallback auf ENV). Returns: True wenn die Signatur gültig ist, False sonst. """ secret = token or os.environ.get("TELEGRAM_BOT_TOKEN", "") if not secret: return False expected = hmac.new( secret.encode("utf-8"), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, hash_val) def validate_and_enqueue( payload: bytes, signature: str, plattform: str, qh: QueueHandler, ) -> dict[str, Any]: """Validiert Signatur und legt eine Submission in die Queue. Führt plattform-spezifische Signaturprüfung durch und gibt ein Ergebnis-Dictionary zurück. Args: payload: Der rohe Webhook-Payload als Bytes. signature: Die Signatur aus den Webhook-Headern. plattform: Die Plattform, entweder "whatsapp" oder "telegram". qh: Der QueueHandler zum Einreihen der Submission. Returns: Dict mit Keys 'success' (bool), 'message' (str), 'submission_id' (str|None). """ if plattform == "whatsapp": if not verify_whatsapp_signature(payload, signature): return { "success": False, "message": "Ungültige WhatsApp-Signatur", "submission_id": None, } elif plattform == "telegram": # Telegram signiert nicht per Header, sondern via hash-Feld im Payload # Für Telegram ist die Validierung hier implizit über das Token pass else: return { "success": False, "message": f"Unbekannte Plattform: {plattform}", "submission_id": None, } return {"success": True, "message": "Validierung erfolgreich", "submission_id": None}