"""Vérifie X-TWA-Signature sur le corps brut d'un webhook TechWatchAlert.

Même calcul que l'envoi (app.core.outbox.signer_webhook) : HMAC-SHA256 du
secret sur ``X-TWA-Timestamp + "." + corps``, préfixe ``sha256=``. Le corps
est celui reçu, octets pour octets. Un horodatage écarté de 300 secondes ou
plus est refusé. L'envoi ne mémorise pas les signatures déjà parties : une
copie renvoyée dans cette fenêtre se vérifie encore.

Usage : python3 verifier_signature.py SECRET HORODATAGE ENTETE < corps
Code 0 si la signature est bonne, 1 si elle est refusée, 2 si l'usage est faux.
"""
from __future__ import annotations

import hashlib
import hmac
import sys
import time

FENETRE_SECONDES = 300


def signature(secret: str, horodatage: str, corps: bytes) -> str:
    mac = hmac.new(secret.encode(), horodatage.encode() + b"." + corps, hashlib.sha256)
    return "sha256=" + mac.hexdigest()


def verifier(
    secret: str,
    horodatage: str,
    corps: bytes,
    entete: str,
    *,
    maintenant: float | None = None,
) -> bool:
    if not horodatage.isdigit():
        return False
    instant = time.time() if maintenant is None else maintenant
    if abs(instant - int(horodatage)) >= FENETRE_SECONDES:
        return False
    return hmac.compare_digest(signature(secret, horodatage, corps), entete)


def main() -> int:
    if len(sys.argv) != 4:
        print(
            "usage: verifier_signature.py SECRET HORODATAGE ENTETE < corps",
            file=sys.stderr,
        )
        return 2
    secret, horodatage, entete = sys.argv[1:]
    corps = sys.stdin.buffer.read()
    ok = verifier(secret, horodatage, corps, entete)
    print("ok" if ok else "refus")
    return 0 if ok else 1


if __name__ == "__main__":
    raise SystemExit(main())
