""" Stateless HMAC-signed confirmation tokens. Token format: base64url( email : unix_timestamp : hmac_sha256 ) No database storage needed — the signature proves authenticity. """ import base64 import hashlib import hmac import time from app.config import settings def generate_token(email: str) -> str: """Create a URL-safe confirmation token for the given email.""" timestamp = str(int(time.time())) payload = f"{email}:{timestamp}" sig = hmac.new( settings.CONFIRM_SECRET.encode(), payload.encode(), hashlib.sha256, ).hexdigest() return base64.urlsafe_b64encode(f"{payload}:{sig}".encode()).decode() def verify_token(token: str) -> str | None: """ Verify a confirmation token. Returns the email if valid, None otherwise. Checks both HMAC signature and expiry. """ try: decoded = base64.urlsafe_b64decode(token.encode()).decode() # rsplit from the right: email may contain colons (unlikely but safe) parts = decoded.rsplit(":", 2) if len(parts) != 3: return None email, timestamp, sig = parts # Verify HMAC expected = hmac.new( settings.CONFIRM_SECRET.encode(), f"{email}:{timestamp}".encode(), hashlib.sha256, ).hexdigest() if not hmac.compare_digest(sig, expected): return None # Check expiry age_seconds = time.time() - int(timestamp) if age_seconds > settings.CONFIRM_TOKEN_EXPIRY_HOURS * 3600: return None if age_seconds < 0: return None # future timestamp — tampered return email except Exception: return None