"""Session-cookie validation that mirrors main.py. Re-implements the verify path so this host-side service can authenticate the same browser cookie that dereth-tracker issues. Both services must share the SECRET_KEY env var. """ from __future__ import annotations import os from fastapi import HTTPException, Request, status from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer # Mirror main.py:996-998 SECRET_KEY = os.getenv("SECRET_KEY", "change-me-in-production-please") SESSION_MAX_AGE = 30 * 24 * 3600 # 30 days _serializer = URLSafeTimedSerializer(SECRET_KEY) def verify_session_cookie(token: str) -> dict | None: """Verify and decode a session token. Returns None if invalid/expired. Mirrors main.py:1013-1019 byte-for-byte so a cookie issued by the tracker decodes here identically. """ try: data = _serializer.loads(token, max_age=SESSION_MAX_AGE) return {"username": data["u"], "is_admin": data["a"]} except (BadSignature, SignatureExpired, KeyError): return None def require_user(request: Request) -> dict: """FastAPI dependency: enforces a valid session cookie. Returns the decoded user dict on success; raises 401 otherwise. """ token = request.cookies.get("session") if not token: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated", ) user = verify_session_cookie(token) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Session invalid or expired", ) return user