User management with login, roles and a Config area #25

Merged
jappel merged 8 commits from feature/user-management into main 2026-09-28 22:43:14 +02:00
Collaborator

Anmeldung und Benutzerverwaltung für die Leistungsbilanz, dazu zwei kleine UI-Anpassungen.

Anmeldung und Benutzer

  • Die ganze App verlangt jetzt eine Anmeldung (Session-Cookie). Es gibt zwei feste Rollen: admin und user.
  • Kein Self-Signup: Admins legen Zugänge unter Config → Benutzer an (Anmeldename, Name, Rolle, Startpasswort). Dort lassen sich auch Rolle und Aktiv-Status ändern und Passwörter zurücksetzen. Unter Config → Konto ändert jeder sein eigenes Passwort.
  • Nach einem Startpasswort oder Reset erzwingt die App beim nächsten Login ein eigenes Passwort.
  • Der erste Admin entsteht nur beim allerersten Start aus AUTH_BOOTSTRAP_USERNAME / AUTH_BOOTSTRAP_PASSWORT, solange die users-Tabelle leer ist. Ohne diese Variablen und ohne Nutzer schreibt der Server beim Start eine Warnung ins Log.
  • In der Seitenleiste gibt es unten den Config-Link (nur für Admins), „Angemeldet als …“ und Hell/Dunkel + Abmelden in einer Reihe, wie in der PM-App. Der Theme-Umschalter ist dafür jetzt ein quadratischer Symbol-Knopf.
  • Neue Migration 0013_users, nur die users-Tabelle. Sie folgt auf 0012_good_gateway aus #3.
  • Doku: docs/authentication.md, mit einer Tabelle der Angriffe und Schutzmaßnahmen.

Absicherung (Details in docs/authentication.md)

  • scrypt mit eigenem Salt je Passwort; unbekannte Anmeldenamen kosten genauso viel Zeit wie bekannte.
  • Login-Drosselung: 5 Fehlversuche je Anmeldename in 15 min, danach HTTP 429.
  • CSRF: SameSite=Lax plus verpflichtender Header X-Leistungsbilanz-Request: 1 für alle Schreibzugriffe; das schützt auch beim HTTP-Zugriff im LAN. Ein vorhandener Sec-Fetch-Site-Header wird zusätzlich geprüft.
  • Neue Session-ID bei Login und Passwortwechsel. Eine Session läuft nach 12 h Inaktivität ab, spätestens nach 7 Tagen.
  • Passwort-Reset und Deaktivieren beenden sofort alle Sessions des Kontos. Der letzte aktive Admin lässt sich nicht herabstufen oder deaktivieren.
  • Längengrenzen vor scrypt, Anmeldenamen nur a-z 0-9 . _ @ -, Header gegen Clickjacking (X-Frame-Options: SAMEORIGIN, frame-ancestors 'self').

Übersicht: Beim Filter der Karten stehen Ein-/Ausklapp-Pfeil, Filterfelder und die Anzahl „x von y“ jetzt in einer Zeile.

Betrieb

  • Neue Umgebungsvariablen in compose.yaml mit Standardwerten: AUTH_BOOTSTRAP_USERNAME, AUTH_BOOTSTRAP_PASSWORT, AUTH_SESSION_HOURS (12), AUTH_SESSION_MAX_DAYS (7), COOKIE_SECURE (false). Hinter HTTPS COOKIE_SECURE=true setzen. Bei Zugriff per http:// im LAN muss es false bleiben, sonst speichert der Browser das Cookie nicht.
  • Die Sessions liegen im Speicher der API, nach einem Neustart müssen sich also alle neu anmelden.

Geprüft auf dem Branch mit dem aktuellen main (inkl. #3): alle drei tsc-Konfigurationen, npm test 576/576 (davon 19 neu in tests/authentication.test.ts), Produktions-Build (build:api + build:web). Zusätzlich per curl gegen einen echten Server: Bootstrap-Admin, erzwungener Passwortwechsel, zweiter Nutzer, Rollenprüfung und Logout. Gegen das Deployment geprüft: 429 nach 5 Fehlversuchen, CSRF-Ablehnung und die Security-Header. Die Funktion läuft seit heute auf der cj-ki-Instanz hinter HTTPS.

🤖 Generated with Claude Code

Nachaudit vor dem Merge

  • aktuellen main einschließlich der überarbeiteten Einspeise-Stromkreise integriert
  • Kontoseite für alle angemeldeten Benutzer freigegeben; Benutzerverwaltung bleibt Admins vorbehalten
  • Letztadmin-Regel in eine atomare SQLite-Transaktion verschoben und mit einem Nebenläufigkeitstest abgesichert
  • scrypt-Parameter und Hashformat strikt begrenzt; beschädigte oder übermäßig teure Hashes werden abgelehnt
  • Domain-Service von Server- und konkreten SQLite-Typen entkoppelt
  • Bootstrap-, HTTP/HTTPS- und Deployment-Dokumentation einschließlich .env.example berichtigt
  • Compose-Konfigurationen, 576 Tests, API-/Web-Build und alle TypeScript-Prüfungen erfolgreich
Anmeldung und Benutzerverwaltung für die Leistungsbilanz, dazu zwei kleine UI-Anpassungen. **Anmeldung und Benutzer** - Die ganze App verlangt jetzt eine Anmeldung (Session-Cookie). Es gibt zwei feste Rollen: `admin` und `user`. - Kein Self-Signup: Admins legen Zugänge unter **Config → Benutzer** an (Anmeldename, Name, Rolle, Startpasswort). Dort lassen sich auch Rolle und Aktiv-Status ändern und Passwörter zurücksetzen. Unter **Config → Konto** ändert jeder sein eigenes Passwort. - Nach einem Startpasswort oder Reset erzwingt die App beim nächsten Login ein eigenes Passwort. - Der erste Admin entsteht nur beim allerersten Start aus `AUTH_BOOTSTRAP_USERNAME` / `AUTH_BOOTSTRAP_PASSWORT`, solange die `users`-Tabelle leer ist. Ohne diese Variablen und ohne Nutzer schreibt der Server beim Start eine Warnung ins Log. - In der Seitenleiste gibt es unten den Config-Link (nur für Admins), „Angemeldet als …“ und Hell/Dunkel + Abmelden in einer Reihe, wie in der PM-App. Der Theme-Umschalter ist dafür jetzt ein quadratischer Symbol-Knopf. - Neue Migration `0013_users`, nur die `users`-Tabelle. Sie folgt auf `0012_good_gateway` aus #3. - Doku: `docs/authentication.md`, mit einer Tabelle der Angriffe und Schutzmaßnahmen. **Absicherung** (Details in `docs/authentication.md`) - scrypt mit eigenem Salt je Passwort; unbekannte Anmeldenamen kosten genauso viel Zeit wie bekannte. - Login-Drosselung: 5 Fehlversuche je Anmeldename in 15 min, danach HTTP 429. - CSRF: SameSite=Lax plus verpflichtender Header `X-Leistungsbilanz-Request: 1` für alle Schreibzugriffe; das schützt auch beim HTTP-Zugriff im LAN. Ein vorhandener `Sec-Fetch-Site`-Header wird zusätzlich geprüft. - Neue Session-ID bei Login und Passwortwechsel. Eine Session läuft nach 12 h Inaktivität ab, spätestens nach 7 Tagen. - Passwort-Reset und Deaktivieren beenden sofort alle Sessions des Kontos. Der letzte aktive Admin lässt sich nicht herabstufen oder deaktivieren. - Längengrenzen vor scrypt, Anmeldenamen nur `a-z 0-9 . _ @ -`, Header gegen Clickjacking (`X-Frame-Options: SAMEORIGIN`, `frame-ancestors 'self'`). **Übersicht:** Beim Filter der Karten stehen Ein-/Ausklapp-Pfeil, Filterfelder und die Anzahl „x von y“ jetzt in einer Zeile. **Betrieb** - Neue Umgebungsvariablen in `compose.yaml` mit Standardwerten: `AUTH_BOOTSTRAP_USERNAME`, `AUTH_BOOTSTRAP_PASSWORT`, `AUTH_SESSION_HOURS` (12), `AUTH_SESSION_MAX_DAYS` (7), `COOKIE_SECURE` (false). Hinter HTTPS `COOKIE_SECURE=true` setzen. Bei Zugriff per `http://` im LAN muss es `false` bleiben, sonst speichert der Browser das Cookie nicht. - Die Sessions liegen im Speicher der API, nach einem Neustart müssen sich also alle neu anmelden. **Geprüft** auf dem Branch mit dem aktuellen `main` (inkl. #3): alle drei `tsc`-Konfigurationen, `npm test` 576/576 (davon 19 neu in `tests/authentication.test.ts`), Produktions-Build (`build:api` + `build:web`). Zusätzlich per curl gegen einen echten Server: Bootstrap-Admin, erzwungener Passwortwechsel, zweiter Nutzer, Rollenprüfung und Logout. Gegen das Deployment geprüft: 429 nach 5 Fehlversuchen, CSRF-Ablehnung und die Security-Header. Die Funktion läuft seit heute auf der cj-ki-Instanz hinter HTTPS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) **Nachaudit vor dem Merge** - aktuellen `main` einschließlich der überarbeiteten Einspeise-Stromkreise integriert - Kontoseite für alle angemeldeten Benutzer freigegeben; Benutzerverwaltung bleibt Admins vorbehalten - Letztadmin-Regel in eine atomare SQLite-Transaktion verschoben und mit einem Nebenläufigkeitstest abgesichert - scrypt-Parameter und Hashformat strikt begrenzt; beschädigte oder übermäßig teure Hashes werden abgelehnt - Domain-Service von Server- und konkreten SQLite-Typen entkoppelt - Bootstrap-, HTTP/HTTPS- und Deployment-Dokumentation einschließlich `.env.example` berichtigt - Compose-Konfigurationen, 576 Tests, API-/Web-Build und alle TypeScript-Prüfungen erfolgreich
Grovy311 added 5 commits 2026-09-28 21:48:43 +02:00
No self-signup: admins create every account in Config -> Benutzer with a
typed start password; a forced password change gates first use. Session-
cookie auth protects all /api/* routes; /api/users additionally requires
the admin role. See docs/authentication.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Square icon-only theme toggle sits next to the Abmelden button in a shared
row, collapsing to just the toggle when the sidebar is collapsed - same
arrangement as pm-app's Sidebar.tsx.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Security: per-username login throttling, constant-time unknown-user check,
Sec-Fetch-Site CSRF guard for writes, session rotation on login and
password change, absolute session lifetime, sessions ended on reset and
deactivation, last-admin protection, input length caps, ASCII usernames,
clickjacking headers. Covered by tests/authentication.test.ts.

Filter panel: toggle, fields and count share one row to save space.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Renumber the users migration to 0013_users so it follows the upstream
0012_good_gateway (logical board feeds); AGENTS.md deferred-work list keeps
both the new feed items and the auth items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also document that Sec-Fetch-Site is only sent over HTTPS, so plain-HTTP
LAN access relies on SameSite=Lax alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jappel added 3 commits 2026-09-28 22:42:23 +02:00
jappel merged commit 68d986ff80 into main 2026-09-28 22:43:14 +02:00
jappel deleted branch feature/user-management 2026-09-28 22:43:15 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: jappel/leistungsbilanz-ts#25
No description provided.