from datetime import datetime, timedelta, timezone from typing import Any from argon2 import PasswordHasher from argon2.exceptions import InvalidHashError, VerificationError, VerifyMismatchError from jose import JWTError, jwt from .config import settings ALGORITHM = "HS256" _password_hasher = PasswordHasher() def hash_password(password: str) -> str: """Создаёт Argon2id-хеш пользовательского пароля.""" return _password_hasher.hash(password) def verify_password(password: str, password_hash: str) -> bool: """Проверяет пароль и безопасно обрабатывает повреждённые хеши.""" try: return _password_hasher.verify(password_hash, password) except (InvalidHashError, VerificationError, VerifyMismatchError): return False def create_access_token(subject: str) -> str: """Создаёт короткоживущий JWT с идентификатором пользователя.""" expires_at = datetime.now(timezone.utc) + timedelta( minutes=settings.access_token_expire_minutes ) payload: dict[str, Any] = {"sub": subject, "exp": expires_at} return jwt.encode(payload, settings.secret_key.get_secret_value(), algorithm=ALGORITHM) def decode_access_token(token: str) -> dict[str, Any] | None: """Проверяет подпись и срок действия JWT.""" try: return jwt.decode( token, settings.secret_key.get_secret_value(), algorithms=[ALGORITHM], ) except JWTError: return None