import secrets from fastapi import APIRouter, HTTPException, status from pydantic import BaseModel from app.core.config import settings router = APIRouter() class LoginRequest(BaseModel): username: str password: str class LoginResponse(BaseModel): token: str @router.post("/admin/login", response_model=LoginResponse) def admin_login(body: LoginRequest): if not settings.ADMIN_USERNAME or not settings.ADMIN_PASSWORD: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Admin account is not configured", ) # constant-time compare to avoid leaking timing info user_ok = secrets.compare_digest(body.username, settings.ADMIN_USERNAME) pass_ok = secrets.compare_digest(body.password, settings.ADMIN_PASSWORD) if not (user_ok and pass_ok): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials", ) # The token IS the password. Single account, no expiry, no rotation — # simple and matches what require_admin() expects in the Authorization # header. Swap for a signed/expiring token if you ever add multiple users. return LoginResponse(token=settings.ADMIN_PASSWORD)