28 lines
933 B
Python
28 lines
933 B
Python
"""Password hashing for the client portal — argon2id via argon2-cffi.
|
|
|
|
Kept separate from portal_auth (cookie signing) so the future operator auth can
|
|
reuse the same hasher. Never store or log raw passwords."""
|
|
import secrets
|
|
from argon2 import PasswordHasher
|
|
from argon2.exceptions import VerifyMismatchError, VerificationError, InvalidHashError
|
|
|
|
_ph = PasswordHasher()
|
|
|
|
|
|
def hash_password(raw: str) -> str:
|
|
"""Return an argon2id hash string for a raw password."""
|
|
return _ph.hash(raw)
|
|
|
|
|
|
def verify_password(raw: str, hashed: str) -> bool:
|
|
"""True iff raw matches the stored hash. Never raises."""
|
|
try:
|
|
return _ph.verify(hashed, raw)
|
|
except (VerifyMismatchError, VerificationError, InvalidHashError, Exception):
|
|
return False
|
|
|
|
|
|
def generate_password(n_bytes: int = 12) -> str:
|
|
"""A strong, URL-safe shareable password (~16 chars for n_bytes=12)."""
|
|
return secrets.token_urlsafe(n_bytes)
|