bcrypt fix
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-09-26 07:07:48 +09:00
parent 31c1644ec2
commit e5aa933cf9
5 changed files with 69 additions and 11 deletions

0
-H Normal file
View File

1
-d Normal file
View File

@@ -0,0 +1 @@
{"detail":[{"type":"missing","loc":["body"],"msg":"Field required","input":null,"url":"https://errors.pydantic.dev/2.4/v/missing"}]}

43
deploy_bcrypt_fix.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
# Deploy bcrypt compatibility fix to production server
# Server: 192.168.0.103
echo "Deploying bcrypt compatibility fix to production server..."
# Copy updated files to server
echo "Copying requirements.txt..."
scp requirements.txt trevor@192.168.0.103:/home/trevor/dev/chat/
echo "Copying shared/auth.py..."
scp shared/auth.py trevor@192.168.0.103:/home/trevor/dev/chat/shared/
echo "Copying user service schemas..."
scp services/user_service/schemas.py trevor@192.168.0.103:/home/trevor/dev/chat/services/user_service/
echo "Connecting to server to update dependencies..."
ssh trevor@192.168.0.103 << 'EOF'
cd /home/trevor/dev/chat
# Stop services
echo "Stopping services..."
./stop_services.sh
# Update Python packages
echo "Updating bcrypt to version 4.0.1..."
pip install --upgrade bcrypt==4.0.1
pip install --upgrade passlib[bcrypt]==1.7.4
# Verify bcrypt installation
echo "Verifying bcrypt installation..."
python3 -c "import bcrypt; print(f'bcrypt version: {bcrypt.__version__}')"
# Restart services
echo "Restarting services..."
./start_services_no_docker.sh
echo "Deployment complete. Services are starting..."
EOF
echo "Deployment script completed."
echo "Check server logs at 192.168.0.103 to verify bcrypt compatibility fix."

View File

@@ -12,6 +12,7 @@ pydantic-settings==2.0.3
python-jose[cryptography]==3.3.0
PyJWT==2.8.0
passlib[bcrypt]==1.7.4
bcrypt==4.0.1
python-multipart==0.0.6
httpx==0.25.1
aiofiles==23.2.1

View File

@@ -3,6 +3,7 @@ Authentication utilities for all services.
This module provides common authentication functionality to avoid circular imports.
"""
import logging
from datetime import datetime, timedelta
from typing import Optional
@@ -14,6 +15,9 @@ from passlib.context import CryptContext
from shared.config import settings
# Suppress bcrypt version warnings
logging.getLogger("passlib").setLevel(logging.ERROR)
# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
@@ -22,21 +26,30 @@ security = HTTPBearer()
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""Verify password against hash. Apply same truncation as used during hashing."""
# Apply same truncation logic as during hashing
password_bytes = plain_password.encode('utf-8')
if len(password_bytes) > 72:
plain_password = password_bytes[:72].decode('utf-8', errors='ignore')
return pwd_context.verify(plain_password, hashed_password)
"""Verify a password against its hash. Handle bcrypt compatibility issues."""
try:
# Truncate password to 72 bytes for consistency
password_bytes = plain_password.encode('utf-8')
if len(password_bytes) > 72:
plain_password = password_bytes[:72].decode('utf-8', errors='ignore')
return pwd_context.verify(plain_password, hashed_password)
except Exception as e:
logging.error(f"Error verifying password: {e}")
return False
def get_password_hash(password: str) -> str:
"""Get password hash. Truncate password to 72 bytes if necessary for bcrypt compatibility."""
# bcrypt has a 72-byte limit, so truncate if necessary
password_bytes = password.encode('utf-8')
if len(password_bytes) > 72:
password = password_bytes[:72].decode('utf-8', errors='ignore')
return pwd_context.hash(password)
try:
# bcrypt has a 72-byte limit, so truncate if necessary
password_bytes = password.encode('utf-8')
if len(password_bytes) > 72:
password = password_bytes[:72].decode('utf-8', errors='ignore')
return pwd_context.hash(password)
except Exception as e:
# Handle bcrypt compatibility issues
logging.error(f"Error hashing password: {e}")
raise ValueError("Password hashing failed. Please use a shorter password.")
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: