From c15176bff47c90a9e4b737cccfa0aa0d68cd023a Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 2 Mar 2026 16:20:36 +0100 Subject: [PATCH] fix: replace passlib with direct bcrypt to fix password hashing crash passlib 1.7.4 is incompatible with bcrypt>=4.1, causing a ValueError during internal bug detection. Using bcrypt directly avoids this. Co-Authored-By: Claude Opus 4.6 --- requirements.txt | 2 +- server/auth.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index ddac990..20605df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ jinja2==3.1.5 websockets==14.2 aiomqtt==2.3.0 python-jose[cryptography]==3.3.0 -passlib[bcrypt]==1.7.4 +bcrypt==4.2.1 diff --git a/server/auth.py b/server/auth.py index 93afc13..2228363 100644 --- a/server/auth.py +++ b/server/auth.py @@ -8,10 +8,10 @@ import secrets from datetime import datetime, timedelta, timezone from typing import Optional +import bcrypt from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from jose import JWTError, jwt -from passlib.context import CryptContext logger = logging.getLogger(__name__) @@ -19,18 +19,17 @@ JWT_SECRET = os.getenv("JWT_SECRET") or secrets.token_urlsafe(32) JWT_ALGORITHM = "HS256" JWT_EXPIRE_HOURS = 24 -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") bearer_scheme = HTTPBearer(auto_error=False) def hash_password(password: str) -> str: """Hash a plain-text password with bcrypt.""" - return pwd_context.hash(password) + return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") def verify_password(plain: str, hashed: str) -> bool: """Verify a plain-text password against its bcrypt hash.""" - return pwd_context.verify(plain, hashed) + return bcrypt.checkpw(plain.encode("utf-8"), hashed.encode("utf-8")) def create_access_token(subject: str) -> str: