"""Auth module — bcrypt password verification and session token management.""" import os import secrets import bcrypt # Module-level defaults (read from env at import time for AUTH_USER/AUTH_PASS_HASH) AUTH_USER: str = os.environ.get("AUTH_USER", "admin@localhost") AUTH_PASS_HASH: str = os.environ.get("AUTH_PASS_HASH", "") # In-memory session store: token -> email _sessions: dict[str, str] = {} def verify_password(password: str) -> bool: """Return True if password matches the bcrypt hash in AUTH_PASS_HASH env var. Reads AUTH_PASS_HASH from env at call time so runtime env changes are respected. Returns False if no hash is configured, if password is empty, or on any error. """ if not password: return False hash_str = os.environ.get("AUTH_PASS_HASH", "") if not hash_str: return False try: return bcrypt.checkpw(password.encode(), hash_str.encode()) except (ValueError, TypeError): return False def create_session_token(email: str) -> str: """Generate a session token, store it mapped to email, and return the token.""" token = secrets.token_hex(32) _sessions[token] = email return token def validate_session_token(token: str) -> str | None: """Return the email for a valid token, or None if token is empty/unknown.""" if not token: return None return _sessions.get(token) def invalidate_session_token(token: str) -> None: """Remove a session token from the store.""" _sessions.pop(token, None)