import logging from fastapi import Depends, HTTPException, status from datetime import datetime, timedelta from jwt import encode from .config.config import settings # Use bcrypt directly instead of passlib for compatibility try: import bcrypt BCRYPT_AVAILABLE = True except ImportError: BCRYPT_AVAILABLE = False logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def hash_password(password: str) -> str: """Hash a password using bcrypt.""" if not BCRYPT_AVAILABLE: logger.warning("bcrypt not available - using plaintext passwords (INSECURE!)") return password # Truncate password to 72 bytes (bcrypt limit) and encode to bytes truncated = password[:72].encode('utf-8') salt = bcrypt.gensalt() hashed = bcrypt.hashpw(truncated, salt) return hashed.decode('utf-8') def verify_password(plain_password: str, hashed_password: str) -> bool: """Verify a password against its hash.""" if not BCRYPT_AVAILABLE: logger.warning("bcrypt not available - using plaintext comparison (INSECURE!)") return plain_password == hashed_password # Truncate password to 72 bytes (bcrypt limit) and encode to bytes truncated = plain_password[:72].encode('utf-8') hashed_bytes = hashed_password.encode('utf-8') return bcrypt.checkpw(truncated, hashed_bytes) def create_access_token(user_id: int, email: str) -> str: """Create a JWT access token.""" to_encode = { "sub": str(user_id), "email": email, "exp": datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) } encoded_jwt = encode(to_encode, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM) return encoded_jwt def get_database(): """ This function is a helper function to simulate getting a database connection. Dependencies are like workers who prepare things for you. """ logger.info("Creating the database connection...") try: yield None finally: logger.info("Closing the database connection...")