single-user login screen

- server/credentials.py: PBKDF2 password + session secret, 0600 json,
  one-time setup command (server refuses to start without it)
- app.py: signed 30-day cookie (itsdangerous), middleware 401s API /
  redirects pages to /login?next=, 5-fail/15-min lockout, /logout
- static/login.html: dark-themed form, inline error display
- app.js: api() 401 -> redirect to /login preserving current URL
- docs: README quick start + features, SPEC auth section
This commit is contained in:
jozamudi committed 2026-08-19 15:54:50 +00:00
1 parent 2c203990bc
commit 76c45a8f29
7 files changed
+181 -6

No files matched your search

+10 -2
View File
@@ -44,7 +44,7 @@ Two moving parts, no database, no framework on the frontend.
## Backend
`server/app.py` + `server/upstream.py`. Python 3.12, deps:
`fastapi`, `uvicorn`, `curl_cffi`.
`fastapi`, `uvicorn`, `curl_cffi`, `itsdangerous`.
- `GET /api/search?q=` → `[{id, slug_id, name, poster}]` (parse step 1)
- `GET /api/anime/{slug_id}` → `{id, name, synopsis, mal_id, seasons:[{slug_id,name,id}]}`
@@ -58,6 +58,12 @@ Two moving parts, no database, no framework on the frontend.
upstream URL. Rewrites every non-comment line of m3u8 bodies to
point back at `/stream/`; proxies master, variants, and segments
(bytes, no transcoding).
- `GET /login` / `POST /login` / `POST /logout` → single-user auth:
PBKDF2-SHA256 password (`server/credentials.py`; hash + session
secret in `server/data/credentials.json`, mode 0600), signed 30-day
cookie, 5-fail/15-min in-memory lockout. Everything else 401s
(API) or redirects to `/login?next=` (pages). Server refuses to
start without credentials.
## Frontend
@@ -89,7 +95,9 @@ Open `http://localhost:8321` (bound to 0.0.0.0 for LAN access).
## Out of scope (v1)
Downloads (`-d`), next-episode countdown (`-N`), syncplay, intro skip,
ani-schedule integration, auth, multi-user, episode titles (not in
ani-schedule integration, multi-user accounts (single shared
password today — per-user history is the natural upgrade), episode
titles (not in
anidb's API — needs a MyAnimeList API key). Add when someone asks.
## Risks