Spaces:
Runtime error
Runtime error
| from fastapi import APIRouter, Depends, HTTPException, Response | |
| from pydantic import BaseModel | |
| from sqlalchemy import select | |
| from sqlalchemy.orm import Session | |
| from app.auth.deps import COOKIE_NAME, enforce_origin, get_current_user, get_settings_dep | |
| from app.auth.jwt import create_token | |
| from app.auth.passwords import verify_password | |
| from app.claimguard import audit | |
| from app.config import Settings | |
| from app.db import get_db | |
| from app.models import AuditEventType, User | |
| router = APIRouter() | |
| class LoginRequest(BaseModel): | |
| email: str | |
| password: str | |
| class UserOut(BaseModel): | |
| id: int | |
| email: str | |
| role: str | |
| full_name: str | |
| def _user_out(user: User) -> UserOut: | |
| return UserOut(id=user.id, email=user.email, role=user.role.value, full_name=user.full_name) | |
| def login( | |
| body: LoginRequest, | |
| response: Response, | |
| session: Session = Depends(get_db), | |
| settings: Settings = Depends(get_settings_dep), | |
| ) -> UserOut: | |
| user = session.scalar(select(User).where(User.email == body.email)) | |
| if user is None or not verify_password(body.password, user.password_hash): | |
| audit.append( | |
| session, | |
| AuditEventType.AUTH_FAILED, | |
| payload={"email": body.email}, | |
| ) | |
| session.commit() | |
| raise HTTPException(status_code=401, detail="Invalid email or password") | |
| token = create_token(user, settings) | |
| response.set_cookie( | |
| COOKIE_NAME, | |
| token, | |
| httponly=True, | |
| samesite="lax", | |
| path="/", | |
| secure=settings.cookie_secure, | |
| max_age=settings.jwt_expire_hours * 3600, | |
| ) | |
| audit.append( | |
| session, | |
| AuditEventType.AUTH_LOGIN, | |
| actor_user_id=user.id, | |
| actor_role=user.role.value, | |
| ) | |
| session.commit() | |
| return _user_out(user) | |
| def logout(response: Response) -> dict[str, str]: | |
| response.delete_cookie(COOKIE_NAME, path="/") | |
| return {"status": "logged_out"} | |
| def me(user: User = Depends(get_current_user)) -> UserOut: | |
| return _user_out(user) | |