"""Signed tokens authorizing the ntfy Approve/Deny callback URLs. ntfy action buttons fire a plain, unauthenticated HTTP request from wherever the notification is received - they carry no Authelia session. The reverse proxy bypass needed for those routes (see README) applies to the whole path, so this token is the ONLY auth on /flights//approve and /reject, including when the request comes from the review page's own buttons. """ import hashlib import hmac import time import models def _secret() -> bytes: return models.get_or_create_secret_key().encode("utf-8") def _signature(flight_id: int, action: str, expiry: int) -> str: message = f"{flight_id}:{action}:{expiry}".encode("utf-8") return hmac.new(_secret(), message, hashlib.sha256).hexdigest() def sign_token(flight_id: int, action: str, ttl_seconds: int = 30 * 86400) -> str: expiry = int(time.time()) + ttl_seconds sig = _signature(flight_id, action, expiry) return f"{expiry}.{sig}" def verify_token(flight_id: int, action: str, token: str) -> bool: if not token or "." not in token: return False expiry_str, _, sig = token.partition(".") try: expiry = int(expiry_str) except ValueError: return False if expiry < time.time(): return False expected = _signature(flight_id, action, expiry) return hmac.compare_digest(expected, sig)