Innebygd innlogging (AUTH_MODE=app) med neon-login og proxy-bypass
Valgfri app-auth ved siden av proxy-modus (default uendret). Signert sesjons-cookie (scrypt-passord, HMAC, ingen avhengigheter), gating av API + WebSocket, og en selvstendig neon-login (public/login.html) for uautentiserte. Trusted bypass: en proxy-identitet (X-Remote-User / Basic Auth) regnes som innlogget uten app-passord (TRUST_PROXY_HEADER, default på), så man kan bootstrappe: logg inn via NPM Basic Auth → sett app-passord i konto-modalen → skru av Basic Auth. Konto-UI for sett/endre passord + logg ut. AUTH_MODE leses per createServer-instans (testbart). 34 integrasjonstester (8 nye for app-auth), alle grønne. README/CLAUDE.md/setup-skript oppdatert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7287f33e47
commit
f6268440d9
9 changed files with 711 additions and 42 deletions
|
|
@ -36,18 +36,21 @@ Nytt mot PHP-versjonen:
|
|||
|
||||
```
|
||||
netops-todo-node/
|
||||
├── server.js Express + ws. REST-API, WebSocket-hub, auth-oppslag.
|
||||
├── server.js Express + ws. REST-API, WebSocket-hub, auth-oppslag/gating.
|
||||
├── lib/store.js Datalager: normalisering, validering, aktivitetslogg,
|
||||
│ atomisk JSON-persistens. Kilden til sannhet for skjema.
|
||||
├── lib/auth.js Innebygd auth: scrypt-passord, signert sesjons-token.
|
||||
├── public/
|
||||
│ ├── index.html Markup. Ingen templating — app.js fyller alt.
|
||||
│ ├── app.js All frontend-logikk (vanilla JS, ingen rammeverk).
|
||||
│ ├── login.html Selvstendig neon-login (AUTH_MODE=app). Inline CSS/JS.
|
||||
│ └── style.css Mørkt tema, samme visuelle identitet som PHP-versjonen.
|
||||
├── seed.json 16 eksempel-oppgaver.
|
||||
├── setup-debian13.sh Engangs-oppsett på Debian 13 LXC (apt + npm ci + systemd).
|
||||
├── test/api.test.js Integrasjonstester (node:test) — REST + WS ende-til-ende.
|
||||
├── data/ Opprettes ved kjøring: tasks.json, activity.json,
|
||||
│ users.json, plans.json, categories.json.
|
||||
│ users.json, plans.json, categories.json,
|
||||
│ auth.json (passordhasher), auth.secret (HMAC-nøkkel).
|
||||
└── README.md Installasjon, proxy-oppsett, API-referanse.
|
||||
```
|
||||
|
||||
|
|
@ -57,9 +60,23 @@ netops-todo-node/
|
|||
brukes kun til push: endringer, presence, editing-signaler.
|
||||
- Én node-prosess eier datakatalogen. Lagring i minnet, skriv til disk er
|
||||
atomisk (tmp + rename) og serialisert gjennom en promise-kjede i `store.js`.
|
||||
- Auth ligger utenfor appen: `X-Remote-User`-header > Basic Auth > cookie
|
||||
(`netops_user`, kan skrus av med `DISABLE_COOKIE_AUTH=1`) > `anon`.
|
||||
Samme oppslag for HTTP og WS-upgrade (`userFromRequest` i server.js).
|
||||
- **To auth-modi** (`AUTH_MODE`, lest per `createServer`-instans så det er
|
||||
testbart):
|
||||
- `proxy` (default): `X-Remote-User` > Basic Auth > `netops_user`-cookie >
|
||||
`anon`. Ingen guard — alt åpent. Bakoverkompatibelt.
|
||||
- `app`: innebygd innlogging. `resolveAuth(req)` → sesjons-cookie
|
||||
(`netops_session`, verifisert i lib/auth.js) ELLER, hvis `TRUST_PROXY_HEADER`,
|
||||
en proxy-identitet (`proxyUser()` = header/Basic, IKKE navn-cookie) som
|
||||
"trusted bypass". En guard-middleware 401-er API og serverer `login.html` på
|
||||
navigasjon når uautentisert. WS-upgrade gates likt.
|
||||
- Bypass-poenget: bootstrap fra Basic Auth → sett app-passord → skru av Basic
|
||||
Auth. `POST /api/auth/password` tillater å sette passord når man er
|
||||
proxy-innlogget; krever nåværende passord kun når man endrer via en app-sesjon.
|
||||
- `resolveAuth` brukes både i HTTP-middleware og WS (`server.on('upgrade')` +
|
||||
`wss.on('connection')`), så samme identitet/gating gjelder begge.
|
||||
- Sesjon: signert cookie `b64url(user).exp.HMAC` (ingen server-side lager).
|
||||
Hemmelighet fra `AUTH_SECRET` eller persistert `data/auth.secret`. Cookie er
|
||||
HttpOnly, SameSite=Lax, Secure når `X-Forwarded-Proto: https`.
|
||||
|
||||
### WebSocket-protokoll (server → klient)
|
||||
|
||||
|
|
@ -153,14 +170,21 @@ strenglengde-klamping, brukernavn-regex `[A-Za-z0-9._@-]{1,64}`), pluss:
|
|||
cookie-auth-modus. Bak proxy-auth gjelder samme vurdering som før
|
||||
(intern bruk OK; offentlig nett → legg på token).
|
||||
- `express.json({ limit: '2mb' })` begrenser payload (import av store lister).
|
||||
- **App-auth (AUTH_MODE=app):** scrypt-hashing + `timingSafeEqual`, signert
|
||||
HMAC-sesjons-cookie (HttpOnly, SameSite=Lax, Secure over https), passord min.
|
||||
6 tegn. Auth-filer (`auth.json`, `auth.secret`) skrives med mode `0600`.
|
||||
`proxyUser()` (bypass-kilden) stoler IKKE på navn-cookien, kun proxy-satte
|
||||
headere. Forutsetning for bypass: app-porten er kun nåbar fra proxyen — sett
|
||||
`TRUST_PROXY_HEADER=0` for å fjerne bypass etter bootstrapping.
|
||||
|
||||
## Vanlige utvidelser
|
||||
|
||||
- **Nytt felt per oppgave:** input i modal (index.html) → `saveForm()` og
|
||||
`parseQuickAdd()` om ønskelig (app.js) → `normalizeTask()` (store.js) →
|
||||
`diffDetail()` for aktivitetsloggen → `renderCard()`/`renderTable()`.
|
||||
- **Ny kategori:** `CATEGORIES`/`CAT_COLORS` i app.js + `VALID_CATEGORIES`
|
||||
i store.js.
|
||||
- **Ny kategori:** egendefinerte legges til i UI-et («+ Ny kategori …») og
|
||||
lagres i categories.json. Nye *innebygde* defaults endres i `DEFAULT_CATEGORIES`
|
||||
(både store.js og app.js har lista; serveren er kilden, app.js har en fallback).
|
||||
- **SQLite:** bytt persistens i `Store` (load/_persist) mot `node:sqlite` —
|
||||
resten av appen er uberørt siden alt går gjennom Store-metodene.
|
||||
- **Varsler ved frist:** server har allerede deadline per task; en
|
||||
|
|
@ -169,13 +193,14 @@ strenglengde-klamping, brukernavn-regex `[A-Za-z0-9._@-]{1,64}`), pluss:
|
|||
|
||||
## Testing-status
|
||||
|
||||
- `npm test`: 26 integrasjonstester (node:test), booter ekte server på
|
||||
tilfeldig port med temp-datakatalog. Dekker normalisering, versjonskonflikt,
|
||||
kommentar-autorisasjon, statuskommentar-på-update, dagsplan (CRUD, per-bruker,
|
||||
validering, scrub ved sletting, dato-fallback, navn, flytt/merge, deling +
|
||||
tilgang, planIndex per viewer), egendefinerte kategorier, aktivitetslogg,
|
||||
WS-broadcast (delt vs. privat plan), persistens, cookie-auth. Alle grønne per
|
||||
2026-06-15 (Node 25).
|
||||
- `npm test`: 34 integrasjonstester (node:test), booter ekte servere på
|
||||
tilfeldig port med temp-datakatalog (én i proxy-modus, én i app-modus). Dekker
|
||||
normalisering, versjonskonflikt, kommentar-autorisasjon, statuskommentar,
|
||||
dagsplan (CRUD, per-bruker, validering, scrub, dato-fallback, navn, flytt/merge,
|
||||
deling + tilgang, planIndex per viewer), egendefinerte kategorier, aktivitetslogg,
|
||||
WS-broadcast (delt vs. privat plan), persistens, cookie-auth, og app-auth
|
||||
(401-guard, login-side på navigasjon, proxy-bypass, passord-bootstrap, sesjon,
|
||||
feil passord, TRUST_PROXY_HEADER=0). Alle grønne per 2026-06-15 (Node 25).
|
||||
- Manuell røyk-test over HTTP: kategori-opprettelse (auto-id + farge), navngitt
|
||||
delt plan, annen brukers tilgang (delt 200 / privat 403), flytt med bevart
|
||||
navn+delingsstatus, og planIndex verifisert.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue