from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from app.core.jwt_denylist import validate_access_claims from app.core.security import decode_access_token from app.modules.users.repository import get_user_by_id bearer = HTTPBearer(auto_error=False) def get_current_user(credentials: HTTPAuthorizationCredentials | None = Depends(bearer)): if credentials is None: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="UNAUTHORIZED") try: payload = decode_access_token(credentials.credentials) validate_access_claims(payload) except ValueError as exc: detail = str(exc) if detail == "TOKEN_REVOKED": raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="TOKEN_REVOKED") raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="INVALID_TOKEN") from exc except Exception as exc: # pragma: no cover - defensive raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="INVALID_TOKEN") from exc user = get_user_by_id(payload["sub"]) if not user: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="UNAUTHORIZED") if user.status == "pending": raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="EMAIL_NOT_VERIFIED") if user.status == "blocked": raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ACCOUNT_BLOCKED") return user def require_admin(user=Depends(get_current_user)): if user.role != "admin": raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ADMIN_ONLY") return user def require_superuser(user=Depends(get_current_user)): if user.role != "admin": raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ADMIN_ONLY") if not user.is_superuser: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="SUPERUSER_ONLY") return user