from __future__ import annotations import secrets from dataclasses import dataclass from datetime import UTC, datetime, timedelta from argon2 import PasswordHasher @dataclass(slots=True) class SessionData: session_id: str csrf_token: str expires_at: datetime role: str username: str class AuthService: def __init__(self) -> None: self._hasher = PasswordHasher() self._sessions: dict[str, SessionData] = {} def hash_password(self, password: str) -> str: return self._hasher.hash(password) def verify_password(self, password: str, password_hash: str) -> bool: try: return self._hasher.verify(password_hash, password) except Exception: return False def create_session(self, username: str, role: str) -> SessionData: session_id = secrets.token_hex(24) csrf_token = secrets.token_hex(16) expires_at = datetime.now(UTC) + timedelta(hours=12) session = SessionData( session_id=session_id, csrf_token=csrf_token, expires_at=expires_at, role=role, username=username, ) self._sessions[session_id] = session return session def get_session(self, session_id: str | None) -> SessionData | None: if session_id is None: return None session = self._sessions.get(session_id) if session is None: return None if session.expires_at < datetime.now(UTC): self._sessions.pop(session_id, None) return None return session