Spaces:
Running
Running
| """DTOs for the ``/auth/*`` endpoints (CONTRACT.md §3, BACKEND_BUILD.md §6). | |
| The wire shapes here are intentionally minimal — auth is a 3-account system | |
| backed by ``credentials.toml`` (see ``src/lib/auth/repo.py``). The frontend | |
| never sees passwords beyond submitting them on login; the session token | |
| lives only in an HttpOnly cookie. ``MeResponse`` is what every authed page | |
| queries on mount to learn who's signed in. | |
| All fields inherit camelCase aliasing via :class:`ApiModel`. | |
| """ | |
| from __future__ import annotations | |
| from .common import ApiModel | |
| class LoginRequest(ApiModel): | |
| """``POST /auth/login`` request body. | |
| Plain-text password on the wire is fine because: (a) v1 runs entirely | |
| on localhost behind the Express proxy (same-origin, HTTP), (b) the | |
| credentials store itself is plain-text by design (see the comment at | |
| the top of ``src/lib/auth/repo.py``), and (c) we use ``hmac.compare_digest`` | |
| on the backend so the comparison is timing-safe. When we split-host | |
| later, TLS terminates at the FE proxy and the password is encrypted | |
| in transit. | |
| """ | |
| username: str | |
| password: str | |
| class MeResponse(ApiModel): | |
| """``GET /auth/me`` (and the ``POST /auth/login`` success body). | |
| The frontend hits ``/auth/me`` on mount to populate ``AuthContext``; a | |
| 401 redirects to ``/login``. ``isAdmin`` drives admin-only UI gating | |
| (Operations pages, Add Book, Re-ingest actions). ``role`` is the full | |
| role string (``admin`` | ``viewer`` | ``reader``) so the FE can | |
| distinguish a low-privilege ``reader`` (Reading-Room-only) from a | |
| read-only ``viewer`` (full library, no paid queries) — ``isAdmin`` alone | |
| can't. ``displayName`` is purely cosmetic — used in the header badge when | |
| present; falls back to the username otherwise. | |
| """ | |
| username: str | |
| is_admin: bool | |
| role: str | |
| display_name: str | None = None | |