52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
import hmac
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Request
|
|
|
|
from app.api.admin.deps import get_admin_claims
|
|
from app.core.errors import ApiError, ErrorCode
|
|
from app.core.request_id import get_or_create_request_id
|
|
from app.core.security import create_jwt
|
|
from fastapi import Depends
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
async def _load_login_json(request: Request) -> tuple[str, str]:
|
|
try:
|
|
data = await request.json()
|
|
except Exception as exc:
|
|
raise ApiError(code=ErrorCode.BAD_REQUEST, message="Invalid JSON body", status_code=400) from exc
|
|
|
|
if not isinstance(data, dict):
|
|
raise ApiError(code=ErrorCode.BAD_REQUEST, message="Invalid JSON body", status_code=400)
|
|
|
|
username = str(data.get("username") or "").strip()
|
|
password = str(data.get("password") or "")
|
|
if not username or not password:
|
|
raise ApiError(code=ErrorCode.BAD_REQUEST, message="Missing credentials", status_code=400)
|
|
|
|
return username, password
|
|
|
|
|
|
@router.post("/login")
|
|
async def login(request: Request) -> dict[str, Any]:
|
|
username, password = await _load_login_json(request)
|
|
settings = request.app.state.settings
|
|
|
|
if username != settings.admin_username or not hmac.compare_digest(password, settings.admin_password):
|
|
raise ApiError(code=ErrorCode.UNAUTHORIZED, message="Invalid credentials", status_code=401)
|
|
|
|
token = create_jwt(secret_key=settings.secret_key, subject=settings.admin_username, ttl_s=3600)
|
|
rid = get_or_create_request_id(request)
|
|
return {"ok": True, "token": token, "request_id": rid}
|
|
|
|
|
|
@router.post("/logout")
|
|
async def logout(request: Request, _claims: dict[str, Any] = Depends(get_admin_claims)) -> dict[str, Any]:
|
|
_ = _claims
|
|
rid = get_or_create_request_id(request)
|
|
return {"ok": True, "request_id": rid}
|