from fastapi import APIRouter, Request, Response from pydantic import BaseModel from config import settings from middleware.auth import ( check_login_rate_limit, create_token, record_login_attempt, ) router = APIRouter(prefix="/auth", tags=["auth"]) class LoginRequest(BaseModel): password: str class LoginResponse(BaseModel): role: str token: str @router.post("/login") async def login(body: LoginRequest, request: Request, response: Response): ip = request.client.host if request.client else "unknown" if not check_login_rate_limit(ip): return _error_response(429, "Too many login attempts. Try again in 1 minute.") record_login_attempt(ip) if body.password == settings.owner_password: role = "owner" elif body.password == settings.guest_password: role = "guest" else: return _error_response(401, "Invalid password") token = create_token(role) # Set httpOnly cookie for web UI response.set_cookie( key="token", value=token, httponly=True, samesite="lax", max_age=settings.jwt_expire_hours * 3600, ) return LoginResponse(role=role, token=token) @router.get("/me") async def me(request: Request): role = getattr(request.state, "role", "anonymous") if role == "anonymous": return _error_response(401, "Not authenticated") return {"role": role} @router.post("/logout") async def logout(response: Response): response.delete_cookie("token") return {"ok": True} def _error_response(status_code: int, message: str): from fastapi.responses import JSONResponse return JSONResponse( status_code=status_code, content={ "error": { "message": message, "type": "auth_error", "code": f"auth_{status_code}", } }, )