Initial commit: webmail client (M0/M1)
Three-pane webmail client. - Backend: FastAPI + async SQLAlchemy + arq worker (Postgres/Redis), IMAP/SMTP sync, threading, search, drafts/outbox with undo, attachments, 2FA. - Frontend: React 18 + Vite + TypeScript + TanStack Query + Tailwind; three-pane UI with rich-text composer, light/dark themes, resizable panels. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
"""Argon2id password hashing (SPEC §6.1, §10.1).
|
||||
|
||||
Params are fixed: ``time_cost=3``, ``memory_cost=64 MiB``, ``parallelism=4``.
|
||||
No other password hashing is permitted anywhere (SPEC §10.1).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from argon2 import PasswordHasher
|
||||
from argon2.exceptions import VerificationError, VerifyMismatchError
|
||||
|
||||
_hasher = PasswordHasher(
|
||||
time_cost=3,
|
||||
memory_cost=64 * 1024, # KiB -> 64 MiB
|
||||
parallelism=4,
|
||||
)
|
||||
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
"""Return an argon2id hash for ``password``."""
|
||||
return _hasher.hash(password)
|
||||
|
||||
|
||||
def verify_password(password_hash: str, password: str) -> bool:
|
||||
"""Constant-time verify ``password`` against ``password_hash``."""
|
||||
try:
|
||||
return _hasher.verify(password_hash, password)
|
||||
except (VerifyMismatchError, VerificationError):
|
||||
return False
|
||||
|
||||
|
||||
def needs_rehash(password_hash: str) -> bool:
|
||||
"""Return True if ``password_hash`` was made with outdated parameters."""
|
||||
return _hasher.check_needs_rehash(password_hash)
|
||||
Reference in New Issue
Block a user