"""Password hashing and token primitives. Passwords use Argon2id (argon2-cffi). Session and email tokens are random high-entropy strings; only their SHA-256 hash is stored, so a database leak never exposes a usable credential. """ import hashlib import secrets from argon2 import PasswordHasher from argon2.exceptions import Argon2Error _hasher = PasswordHasher() def hash_password(password: str) -> str: return _hasher.hash(password) def verify_password(password_hash: str, password: str) -> bool: try: return _hasher.verify(password_hash, password) except (Argon2Error, ValueError): return False def generate_token() -> str: """A URL-safe, high-entropy token (the raw secret handed to the client).""" return secrets.token_urlsafe(32) def hash_token(token: str) -> str: """SHA-256 of a token — what we store and look up by.""" return hashlib.sha256(token.encode("utf-8")).hexdigest()