"""Аутентификация: хеширование паролей, проверка, сессии, валидация.""" from __future__ import annotations import hashlib import hmac import re import secrets PBKDF2_ITERATIONS = 200_000 EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$") MIN_PASSWORD = 8 def hash_password(password: str, iterations: int = PBKDF2_ITERATIONS) -> str: salt = secrets.token_bytes(16) dk = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations) return f"pbkdf2_sha256${iterations}${salt.hex()}${dk.hex()}" def verify_password(password: str, stored: str | None) -> bool: if not stored: return False try: algo, iters, salt_hex, digest = stored.split("$") if algo != "pbkdf2_sha256": return False dk = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), bytes.fromhex(salt_hex), int(iters)) return hmac.compare_digest(dk.hex(), digest) except (ValueError, AttributeError): return False def new_token() -> str: return secrets.token_urlsafe(32) def valid_email(email: str) -> bool: email = (email or "").strip() return bool(EMAIL_RE.match(email)) and len(email) <= 254 def validate_registration(email: str, password: str) -> str | None: """Вернуть текст ошибки или None, если всё хорошо.""" if not valid_email(email): return "Некорректный email" if len(password or "") < MIN_PASSWORD: return f"Пароль должен быть не короче {MIN_PASSWORD} символов" return None