"""platform/session — stateless signed session tokens (SD-0001 §6.2). Sessions are signed HTTP-only cookies; there is no session table. A token is `base64url(payload_json).base64url(hmac_sha256(payload))` keyed by the configured session secret (INV-8). `verify` checks the MAC in constant time and returns the payload dict, or None for any malformed/tampered/wrong-key token. No server-side state to revoke — a leaked secret is rotated, invalidating every session at once (§6.2, accepted at MVP scale). """ from __future__ import annotations import base64 import hashlib import hmac import json from typing import Any def _b64e(raw: bytes) -> str: return base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii") def _b64d(s: str) -> bytes: pad = "=" * (-len(s) % 4) return base64.urlsafe_b64decode(s + pad) def _mac(payload_b64: str, secret: str) -> str: digest = hmac.new(secret.encode("utf-8"), payload_b64.encode("ascii"), hashlib.sha256).digest() return _b64e(digest) def sign(payload: dict[str, Any], secret: str) -> str: """Serialize and sign a session payload into a cookie-safe token.""" payload_b64 = _b64e(json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")) return f"{payload_b64}.{_mac(payload_b64, secret)}" def verify(token: str, secret: str) -> dict[str, Any] | None: """Return the payload if the token's signature is valid, else None.""" if not token or "." not in token: return None payload_b64, _, sig = token.partition(".") expected = _mac(payload_b64, secret) if not hmac.compare_digest(sig, expected): return None try: return json.loads(_b64d(payload_b64)) except (ValueError, json.JSONDecodeError): return None