import bcrypt from datetime import datetime, timedelta from jose import JWTError, jwt from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials SECRET_KEY = "rips-manager-secret-key-change-in-production" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_HOURS = 12 security = HTTPBearer(auto_error=False) def hash_password(password: str) -> str: return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() def verify_password(password: str, password_hash: str) -> bool: return bcrypt.checkpw(password.encode(), password_hash.encode()) def create_token(user_id: int, username: str) -> str: payload = { "user_id": user_id, "username": username, "exp": datetime.utcnow() + timedelta(hours=ACCESS_TOKEN_EXPIRE_HOURS), } return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) from typing import Optional def decode_token(token: str) -> Optional[dict]: try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) return payload except JWTError: return None from fastapi import Request def get_current_user(request: Request, credentials: HTTPAuthorizationCredentials = Depends(security)): if hasattr(request.state, "user") and request.state.user: return request.state.user if credentials is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated", ) payload = decode_token(credentials.credentials) if payload is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token", ) return payload def optional_user(request: Request, credentials: HTTPAuthorizationCredentials = Depends(security)): if hasattr(request.state, "user") and request.state.user: return request.state.user if credentials is None: return None return decode_token(credentials.credentials)