From d3f6736a2b0b2f541e19d866730529a88f953ff9 Mon Sep 17 00:00:00 2001 From: Damir Date: Wed, 8 Apr 2026 00:44:43 +0300 Subject: [PATCH] argon --- backend/auth.py | 28 ++++++---------------------- backend/main.py | 8 -------- backend/requirements-backend.txt | 7 ++----- 3 files changed, 8 insertions(+), 35 deletions(-) diff --git a/backend/auth.py b/backend/auth.py index 07f499d..e57c1da 100644 --- a/backend/auth.py +++ b/backend/auth.py @@ -1,7 +1,6 @@ from __future__ import annotations import os -import hashlib from datetime import datetime, timedelta, timezone from fastapi import Depends, HTTPException @@ -13,10 +12,10 @@ from sqlalchemy.orm import Session from backend.db import get_db from backend.models import User -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +pwd_context = CryptContext(schemes=["argon2"], deprecated="auto") bearer = HTTPBearer(auto_error=False) -AUTH_VERSION = "prehash-sha256-2026-04-07" +AUTH_VERSION = "argon2-2026-04-07" def _env(name: str, default: str) -> str: @@ -29,38 +28,23 @@ JWT_ALG = _env("JWT_ALG", "HS256") JWT_EXPIRES_MINUTES = int(_env("JWT_EXPIRES_MINUTES", "480")) # 8h -def _bcrypt_safe_password(password: str) -> str: - """ - bcrypt only uses first 72 bytes of the input. - To support long passwords safely, pre-hash using SHA-256 when needed. - """ - raw = password.encode("utf-8") - if len(raw) <= 72: - return password - return hashlib.sha256(raw).hexdigest() - - def hash_password(password: str) -> str: - safe = _bcrypt_safe_password(password) try: - return pwd_context.hash(safe) + return pwd_context.hash(password) except Exception as e: orig_len = len(password.encode("utf-8")) - safe_len = len(safe.encode("utf-8")) raise RuntimeError( - f"{str(e)} (orig_bytes_len={orig_len}, safe_bytes_len={safe_len}, safe_type={type(safe).__name__})" + f"{str(e)} (orig_bytes_len={orig_len})" ) from e def verify_password(password: str, password_hash: str) -> bool: - safe = _bcrypt_safe_password(password) try: - return pwd_context.verify(safe, password_hash) + return pwd_context.verify(password, password_hash) except Exception as e: orig_len = len(password.encode("utf-8")) - safe_len = len(safe.encode("utf-8")) raise RuntimeError( - f"{str(e)} (orig_bytes_len={orig_len}, safe_bytes_len={safe_len}, safe_type={type(safe).__name__})" + f"{str(e)} (orig_bytes_len={orig_len})" ) from e diff --git a/backend/main.py b/backend/main.py index cd0b5c4..50e4291 100644 --- a/backend/main.py +++ b/backend/main.py @@ -33,12 +33,6 @@ from backend.db import engine, get_db # noqa: E402 from backend.models import Base, User # noqa: E402 -def _password_ok_or_400(password: str): - # bcrypt has a 72-byte input limit (bytes, not chars) - if len(password.encode("utf-8")) > 72: - raise HTTPException(status_code=400, detail="Password is too long (max 72 bytes for bcrypt)") - - class GenerationRequest(BaseModel): description: str platform: str = "GitHub Actions" # or GitLab CI @@ -94,7 +88,6 @@ def register(req: RegisterRequest, db: Session = Depends(get_db)): if not email or not req.password: raise HTTPException(status_code=400, detail="Email and password are required") pw_bytes_len = len(req.password.encode("utf-8")) - _password_ok_or_400(req.password) try: exists = db.execute(select(User).where(User.email == email)).scalar_one_or_none() @@ -130,7 +123,6 @@ def login(req: LoginRequest, db: Session = Depends(get_db)): email = req.email.strip().lower() if not req.password: raise HTTPException(status_code=400, detail="Password is required") - _password_ok_or_400(req.password) try: user = db.execute(select(User).where(User.email == email)).scalar_one_or_none() if not user or not verify_password(req.password, user.password_hash): diff --git a/backend/requirements-backend.txt b/backend/requirements-backend.txt index 499f24e..dec289f 100644 --- a/backend/requirements-backend.txt +++ b/backend/requirements-backend.txt @@ -4,10 +4,7 @@ requests pyyaml sqlalchemy psycopg[binary] -passlib[bcrypt] +passlib[argon2] +argon2-cffi python-jose[cryptography] pydantic[email] -fastapi -uvicorn[standard] -requests -pyyaml