netops/netops-todo-node
Jon Vanvik 3f69cd4248 Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon
Auth (app-modus):
- Roller admin/standard. Admin oppretter/sletter kontoer, resetter passord,
  endrer roller (konto-modal). Eksisterende brukere → admin ved migrering;
  bootstrap-bruker via proxy-bypass → admin. Siste admin vernet.
- Tilbakekalling via per-bruker epoke i tokenet: passordbytte, admin-reset,
  «Logg ut alle enheter» og sletting dreper alle aktive sesjoner. Token-format
  endret (3- → 4-delt) — alle logges ut én gang ved oppgradering.

Dagsplan: søkbar/velgbar planliste («📋 Planer») avledet fra planIndex —
finn plan på navn/dato/person uten å gjette dato.

GUI: login-neon trukket inn i hovedappen (header/knapper/KPI-kanter), og
login-siden fikk mer tech (HUD-hjørner, glitch-tittel, scanlines).

40 integrasjonstester (6 nye), alle grønne. README + CLAUDE.md oppdatert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 14:56:39 +02:00
..
lib Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon 2026-06-15 14:56:39 +02:00
public Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon 2026-06-15 14:56:39 +02:00
test Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon 2026-06-15 14:56:39 +02:00
.gitignore Legg til Node/npm-versjon med sanntidssynk + Debian 13-oppsettsskript 2026-06-12 11:54:22 +02:00
CLAUDE.md Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon 2026-06-15 14:56:39 +02:00
package-lock.json Legg til Node/npm-versjon med sanntidssynk + Debian 13-oppsettsskript 2026-06-12 11:54:22 +02:00
package.json Legg til Node/npm-versjon med sanntidssynk + Debian 13-oppsettsskript 2026-06-12 11:54:22 +02:00
README.md Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon 2026-06-15 14:56:39 +02:00
seed.json Legg til Node/npm-versjon med sanntidssynk + Debian 13-oppsettsskript 2026-06-12 11:54:22 +02:00
server.js Auth-herding: roller, kontoadmin, token-revokering + søkbar planliste + neon 2026-06-15 14:56:39 +02:00
setup-debian13.sh Innebygd innlogging (AUTH_MODE=app) med neon-login og proxy-bypass 2026-06-15 14:27:13 +02:00

NetOps To-Do (Node-versjon)

Sanntids oppgavetavle for et nettverksdrift-team. Node + Express + WebSockets. Endringer fra én bruker dukker opp hos alle andre umiddelbart — ingen polling, ingen manuell refresh.

Kom i gang

npm install
npm start            # → http://localhost:3000

Utvikling med auto-restart ved kodeendring:

npm run dev

Tester:

npm test

Miljøvariabler

Variabel Default Beskrivelse
PORT 3000 HTTP-port
HOST 0.0.0.0 Lytteadresse
DATA_DIR ./data Datakatalog (tasks/activity/users/plans/categories/auth)
AUTH_MODE proxy proxy = stol på proxy-header/Basic Auth. app = innebygd innlogging (sesjons-cookie + passord)
TRUST_PROXY_HEADER 1 I app-modus: la en proxy-identitet (X-Remote-User / Basic) slippe inn uten app-passord (for bootstrapping). Sett 0 for å slå av
SESSION_TTL_DAYS 30 Levetid på app-sesjons-cookien
AUTH_SECRET (auto) HMAC-nøkkel for sesjons-cookies. Settes ikke den, genereres og lagres i data/auth.secret
DISABLE_COOKIE_AUTH (av) Proxy-modus: 1 skrur av selvvalgt navn via cookie — da gjelder kun proxy-headere

Autentisering

To modi, styrt av AUTH_MODE.

proxy (default) — auth utenfor appen

Brukernavn hentes, i prioritert rekkefølge:

  1. X-Remote-User-header — satt av reverse proxy (oauth2-proxy, Authelia, …)
  2. Authorization: Basic — Basic Auth terminert i proxy, brukernavnet gjenbrukes
  3. netops_user-cookie — selvvalgt navn via "Sett navn"-knappen (hjemme/dev-bruk)
  4. anon

For team-bruk bak proxy: sett DISABLE_COOKIE_AUTH=1 så ingen kan velge navn selv.

app — innebygd innlogging

Egen neon-login (/login) med passord. Sesjon er en signert, langlevd cookie (SESSION_TTL_DAYS, default 30) — ingen repeterte Basic Auth-prompts, og virker sømløst med WebSocket. Passord hashes med scrypt (Node-kjerne, ingen avhengigheter), lagret i data/auth.json.

Roller: admin og standard. Admin kan opprette/slette kontoer, tilbakestille passord og endre roller (brukermenyen oppe til høyre → admin-seksjon). Standard kan endre eget passord og logge ut alle enheter. Ved oppgradering blir alle eksisterende brukere automatisk admin, og den første som setter passord via proxy-bypass blir admin (bootstrap). Den siste administratoren kan ikke slettes eller degraderes.

Tilbakekalling (herding): hver bruker har en «epoke» bakt inn i tokenet. Passordbytte, admin-reset og «Logg ut alle enheter» bumper epoken og dreper alle eksisterende sesjoner umiddelbart (sletting av konto gjør det samme). Sesjons-cookien er HttpOnly + SameSite=Lax + Secure (over HTTPS) og signert med HMAC, så den kan ikke forfalskes. (Etter denne oppgraderingen logges alle ut én gang, siden token-formatet endret seg.)

Trusted bypass / migrering fra Basic Auth: Når TRUST_PROXY_HEADER=1 (default) regnes en proxy-identitet (X-Remote-User eller Basic Auth) som innlogget, selv uten app-passord. Det gir en trygg overgang:

  1. Behold NPM Access List (Basic Auth) og deploy med AUTH_MODE=app.
  2. Åpne appen (du slipper inn via Basic Auth-bypass), klikk brukernavnet ditt oppe til høyre → sett et app-passord. Gjenta for hver kollega.
  3. Fjern NPM Access List. Nå møtes alle av neon-login og logger inn med passordet.

Bypass krever at app-porten kun er nåbar fra proxyen (samme antakelse som proxy-modus). Vil du være streng, sett TRUST_PROXY_HEADER=0 etter at alle har satt passord — da gjelder kun app-sesjoner.

Oppsett som tjeneste: legg Environment=AUTH_MODE=app i systemd-enheten (se under), eller kjør skriptet med AUTH_MODE=app bash setup-debian13.sh.

Rask installasjon på Debian 13 (LXC/VM)

# Som root i containeren:
apt-get update && apt-get install -y git
git clone <din-remote> /opt/netops
bash /opt/netops/netops-todo-node/setup-debian13.sh

setup-debian13.sh installerer Node fra apt, kjører npm ci og setter opp systemd-tjenesten (DynamicUser + StateDirectory, data i /var/lib/netops-todo). Kjør skriptet på nytt etter git pull for å oppgradere. Med proxy-auth: DISABLE_COOKIE_AUTH=1 bash setup-debian13.sh.

Bak reverse proxy

WebSocket-endepunktet er /ws og krever upgrade-støtte i proxyen. Appen må ligge på rota av et (sub)domene (f.eks. todo.hjemme.lan) — frontend bruker absolutte stier, så sti-prefiks (proxy.lan/todo/) fungerer ikke.

Nginx Proxy Manager

  1. Hosts → Proxy Hosts → Add Proxy Host
    • Domain Names: todo.dittdomene.no
    • Scheme: http · Forward Hostname/IP: LXC-ens IP · Forward Port: 3000
    • Websockets Support: PÅ (påkrevd — sanntidssynken bruker /ws)
    • Cache Assets: AV (ellers kan gammel app.js serveres etter oppgradering)
    • Block Common Exploits: valgfritt, fungerer fint sammen med appen
  2. SSL-fanen: Request a new SSL Certificate (Let's Encrypt) + Force SSL. Frontend bytter selv til wss: når siden er https.
  3. Auth — to alternativer:
    • Innebygd app-innlogging (anbefalt — slipper repeterte Basic Auth-prompts): kjør tjenesten med AUTH_MODE=app. Bruk gjerne NPM Access List midlertidig for å bootstrappe (se «app»-seksjonen over), og fjern den når alle har satt passord. Da trenger ikke NPM Access List i det hele tatt.
    • Proxy Basic Auth: Access Lists → lag brukere og knytt til proxy-hosten. NPM sender Authorization-headeren videre og appen bruker brukernavnet derfra. Sett DISABLE_COOKIE_AUTH=1. (Ulempe: nettleseren spør om passord på nytt ved hver ny økt — derav app-innlogging som alternativ.)

nginx:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Remote-User $remote_user;   # ved basic auth i nginx
}

Apache (mod_proxy_wstunnel):

ProxyPass        /ws ws://127.0.0.1:3000/ws
ProxyPassReverse /ws ws://127.0.0.1:3000/ws
ProxyPass        /   http://127.0.0.1:3000/
ProxyPassReverse /   http://127.0.0.1:3000/
RequestHeader set X-Remote-User %{REMOTE_USER}s

Kjør som tjeneste (systemd)

# /etc/systemd/system/netops-todo.service
[Unit]
Description=NetOps To-Do
After=network.target

[Service]
# DynamicUser + StateDirectory: systemd lager bruker og /var/lib/netops-todo
# med riktige rettigheter automatisk — ingen useradd/chown nødvendig.
DynamicUser=yes
StateDirectory=netops-todo
WorkingDirectory=/opt/netops-todo
ExecStart=/usr/bin/node server.js
Environment=PORT=3000
# HOST=127.0.0.1 hvis proxyen kjører på samme maskin. Står proxyen i en annen
# container/host: fjern linjen (lytt på alt) og brannmur port 3000 til kun proxyen.
Environment=HOST=127.0.0.1
Environment=DATA_DIR=/var/lib/netops-todo
# Innebygd innlogging (anbefalt). Bytt til proxy-modus ved å fjerne denne
# og evt. sette DISABLE_COOKIE_AUTH=1.
Environment=AUTH_MODE=app
Restart=on-failure

[Install]
WantedBy=multi-user.target

Funksjoner

  • Sanntidssynk — alle endringer pushes til alle åpne faner via WebSocket
  • Presence — se hvem som er pålogget akkurat nå
  • Kanban-tavle med drag & drop mellom statuskolonner, pluss klassisk tabellvisning
  • Dagsplan — plukk oppgaver fra lista og bygg en ordnet plan for dagen (dra for å sortere, kapasitet i timer, datovelger). Kan navngis, flyttes til en annen dato i ett klikk, og er som hovedregel synlig for alle (med en «Synlig for alle»-toggle for å gjøre den privat). Andres delte planer kan ses skrivebeskyttet via «Plan for»-velgeren. Søkbar planliste📋 Planer») for å finne en plan på navn/dato/person uten å gjette datoen.
  • Brukerkontoer med roller (i app-auth-modus) — admin kan opprette kontoer, resette passord og styre roller; «Logg ut alle enheter» tilbakekaller økter.
  • Plan-badge på oppgaver — hvert kort/rad viser om oppgaven er planlagt, hvilken dag og av hvem.
  • Egendefinerte kategorier — legg til nye kategorier fra kategori-nedtrekket («+ Ny kategori …»); de deles med hele teamet umiddelbart.
  • Feltmodus — toggle (📱 / f) for større knapper og mer tommelvennlig layout på mobil; slås på automatisk på små skjermer.
  • Kommentar ved statusbytte — når du markerer ferdig eller blokkert (via knapp, kanban-drag eller modal) tilbys du å skrive en kommentar som festes til oppgaven og vises i aktivitetsloggen
  • Hurtig-registrering med tokens: Bytt SFP #l1 p2 @me !imorgen ~1h loc:DC-OSL-1
  • Kommentarer per oppgave
  • Aktivitetslogg — hvem gjorde hva, når (sidepanel)
  • Konfliktdeteksjon — versjonsnummer per oppgave; lagring fra utdatert versjon avvises med tydelig varsel i stedet for stille overskriving
  • "Redigerer nå"-indikator — ser om en kollega har samme oppgave åpen
  • Angre sletting direkte fra toast
  • KPI-er, grafer (kategori/prioritet/eier), filtre, sortering, søk
  • Eksport/import av JSON, eksempeldata for demo
  • Tastatursnarveier: n ny · / søk · v bytt visning · p dagsplan · f feltmodus · a aktivitet · esc lukk

API

Alle endepunkt under /api/, JSON inn/ut. v er versjonsnummer for optimistisk låsing — send med ved update, få 409 hvis noen andre har lagret.

Metode Endepunkt Beskrivelse
GET /api/state Bruker, auth-status, oppgaver, aktivitet, kjente brukere, online, kategorier, dagens plan, planIndex
GET /api/auth/status Auth-modus, innlogget?, bruker, via, har passord
POST /api/auth/login App-innlogging { user, password } → sesjons-cookie
POST /api/auth/logout Tøm sesjons-cookie (denne enheten)
POST /api/auth/logout-all Tilbakekall alle egne økter (bump epoke), behold denne
POST /api/auth/password Sett/endre eget passord { password, current? }
GET /api/auth/users (admin) Liste over kontoer
POST /api/auth/users (admin) Opprett konto { user, password, role }
POST /api/auth/users/:user/password (admin) Tilbakestill passord (logger ut brukeren)
PUT /api/auth/users/:user/role (admin) Sett rolle { role }
DELETE /api/auth/users/:user (admin) Slett konto
POST /api/tasks Opprett oppgave (title påkrevd)
PUT /api/tasks/:id Oppdater (delvis OK; send v for konfliktsjekk; valgfri comment festes som status-kommentar)
DELETE /api/tasks/:id Slett
POST /api/tasks/:id/comments Legg til kommentar { text }
DELETE /api/tasks/:id/comments/:cid Slett egen kommentar
GET /api/plan?date=YYYY-MM-DD&user=navn Hent dagsplan (egen, eller en annens hvis delt — ellers 403)
PUT /api/plan Lagre egen dagsplan { date, items: [id…], name?, shared? }
PUT /api/plan/share Slå deling av/på { date, shared }
PUT /api/plan/move Flytt hele planen { from, to } (slår sammen på måldato)
POST /api/categories Legg til egendefinert kategori { name, color? }
POST /api/replace Erstatt hele listen (import)
POST /api/seed Last eksempeldata (kun hvis tomt)
POST /api/login Sett navn-cookie (hvis cookie-auth er på)
GET /healthz Helsesjekk

Eksempel:

curl -s -X POST localhost:3000/api/tasks \
  -H 'Content-Type: application/json' \
  -H 'X-Remote-User: jon' \
  -d '{"title":"Sjekk BGP-sesjon mot AS2119","category":"BGP","priority":"P1"}'

Lagring

JSON-filer i DATA_DIR (atomisk skriv via tmp-fil + rename, serialisert i prosessen): tasks.json, activity.json, users.json, plans.json (dagsplaner {name, items, shared} per bruker per dato; eldre enn 30 dager ryddes ved oppstart) og categories.json (egendefinerte kategorier). Én node-prosess per datakatalog. Holder fint til tusenvis av oppgaver; blir det trangt er SQLite (node:sqlite) neste naturlige steg.