diora-web/docs/accounts.md
mrwnslz 67f983dd1c
Some checks failed
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 11m27s
Test / e2e (push) Failing after 1m30s
Nach dem Authelia-Login sind die Bücher gleich offen, ohne Code und Passwort (sw CACHE v162)
Authelia gibt dem Gerät (nicht dem diora-Server) ein geheimes Attribut
heraus. Damit legt das Gerät beim Verknüpfen den Bücher-Schlüssel
verschlüsselt bei diora ab und holt ihn auf neuen Geräten nach dem
Authelia-Login unsichtbar zurück. Code und Passwort bleiben als Notweg, wenn
Authelia nichts liefert. Aktiv, sobald DIORA_OIDC_APP_CLIENT_ID gesetzt ist.

Details und Grenzen: docs/accounts.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 19:35:21 +01:00

5.3 KiB

Anmeldung und Bücher-Schlüssel

Zwei Wege hinein

Benutzername und Passwort (accounts/views.py login_view): Das Login-Formular leitet im Browser aus dem Passwort den Bücher-Schlüssel ab (PBKDF2-SHA256, Salt diora:<username>, 200 000 Runden) und legt ihn bis zur nächsten Seite in localStorage['diora_pending_enc_key'] ab. Die App-Seite übernimmt ihn als diora_enc_key_<userId> (32-crypto.js, 99-init.js).

Authelia (OpenID Connect) (accounts/oidc.py, accounts/oidc_views.py): als zusätzlicher Weg, die Anmeldung mit Passwort bleibt. Der Ablauf ist Authorization Code mit PKCE (S256) und einem vertraulichen Client (client_secret_basic). Das id_token wird hier geprüft (RS256 gegen die JWKS des Anbieters, iss, aud, exp, nonce), dafür reicht cryptography.

  • Ein Konto wird einmal verknüpft: in den Einstellungen „Mit Authelia verknüpfen“, während man normal angemeldet ist (/accounts/oidc/start/?link=1). Gespeichert wird OidcIdentity (issuer, sub; Name und Mail nur zur Anzeige). Danach führt „Mit Authelia anmelden“ auf der Login-Seite in dieses Konto.
  • Eine nicht verknüpfte Authelia-Identität wird abgewiesen. Es entstehen keine neuen Konten über Authelia, und es wird auch nicht über Name oder Mail automatisch verknüpft.
  • Wer hinein darf, regelt Authelia (Policy mitglieder = Gruppen admins oder freunde).
  • Einstellungen per Umgebung: DIORA_OIDC_ISSUER, DIORA_OIDC_CLIENT_ID, DIORA_OIDC_CLIENT_SECRET, DIORA_OIDC_REDIRECT_URI (fest, weil hinter dem Proxy kein https erkannt wird), optional DIORA_OIDC_PROVIDER_NAME. Fehlt eins der ersten drei, gibt es keinen Knopf. Auf prod stehen sie in ~/docker-compose/diora-prod/.env (Strato), das Gegenstück liegt auf Hetzner in /opt/authelia/oidc-clients.env.
  • Redirect-URI im Authelia-Client: https://diora.creamfresh.xyz/accounts/oidc/callback/.

Der Schlüssel nach einer Authelia-Anmeldung

Normalfall: über Authelia, ohne Nachfrage

Authelia hält je Nutzer ein geheimes Attribut diora_key (32 Byte, base64). Es geht nur an den öffentlichen Client diora-app (DIORA_OIDC_APP_CLIENT_ID, PKCE, Scope diora_key) und nur über userinfo, nicht im id_token. Nach jedem Authelia-Login (und nach dem Verknüpfen) führt diora auf /accounts/oidc/key/ (templates/accounts/oidc_key.html). Die Seite meldet sich im Browser noch einmal mit prompt=none als diora-app an, unsichtbar, weil die Authelia-Sitzung noch besteht, und holt per CORS Token und userinfo. Daraus leitet sie mit HKDF-SHA256 (Salt = sub, info diora authelia key v1) einen AES-GCM-Schlüssel ab:

  • Hat das Gerät den Bücher-Schlüssel (und passt er zu einem Buch), wird er damit verschlüsselt und im Vault authelia-key abgelegt, bei jedem Authelia-Login neu. So heilt ein geänderter diora_key von selbst.
  • Hat es keinen, öffnet sie den Vault-Eintrag damit und legt den Schlüssel ab.
  • Es zählt nur das Authelia-Konto, das mit diesem diora-Konto verknüpft ist (sub).

Der diora-Server sieht diora_key nie. Grenze, ehrlich: Wer Authelia (Hetzner-Root) oder dein Authelia-Konto (Passwort, Mail-Reset) übernimmt, kommt damit an die Bücher. Wer Strato übernimmt, kann im Browser ohnehin manipuliertes JS ausliefern. Geschützt ist gegen geleakte Daten einer Seite (diora-DB/Backup ohne Authelia-Nutzerdatei oder umgekehrt). Geht diora_key verloren, sind die Bücher nicht weg: Der Schlüssel kommt weiter aus dem Passwort. Entschieden 2026-11-01 vom Nutzer (Komfort vor stärkerer Trennung).

Notweg: Code oder Passwort

Ohne Passwort gibt es keinen Schlüssel. Deshalb erzeugt getOrCreateEncKey() nie mehr selbst einen neuen Schlüssel: Früher machte es einen zufälligen, wenn keiner da war, und damit waren die vorhandenen Bücher auf diesem Gerät verloren. Jetzt fragt es dioraUnlock() (static/js/app/33-unlock.js). Es gibt zwei Wege:

  1. Von einem entsperrten Gerät übergeben (accounts/keyshare.py, Modell KeyShare). Das neue Gerät schickt einen ECDH-P-256-Public-Key und zeigt einen 6-stelligen Code, der aus diesem Key berechnet wird. Entsperrte Geräte fragen alle 15 s /accounts/keyshare/pending/ ab und zeigen denselben Code mit „Freigeben/Ablehnen“. Die Freigabe verschlüsselt den Bücher-Schlüssel mit AES-GCM unter dem gemeinsamen Geheimnis (HKDF-SHA256, info diora keyshare v1). Der Server sieht nur Public Keys und Chiffrat und gibt die Antwort genau einmal heraus. Anträge laufen nach 10 min ab. Angeboten werden nur solche, deren Gerät in den letzten 20 s nachgefragt hat, und je Konto höchstens 5, die ältesten weichen.
  2. Das diora-Passwort einmal eingeben: dieselbe Ableitung wie beim Login.

In beiden Fällen wird der Schlüssel an einem Buch geprüft, bevor er gespeichert wird. Mit „Später“ bleiben Bücher gesperrt, und die Bibliothek zeigt einen Knopf „Entsperren“. Die Einstellungsseite erzeugt ebenfalls keinen Schlüssel mehr.

Apps

Android und Desktop melden sich bisher nur mit Passwort an (eigene Login-Seiten in diora-android/web-native/login.html und diora-desktop/src/web/login.js, die einen API-Token holen). Authelia für die Apps folgt als eigener Schritt: Login im Systembrowser als diora-app mit PKCE, Redirect xyz.creamfresh.diora:/oauth, xyz.creamfresh.diora.reader:/oauth bzw. Loopback http://127.0.0.1:<port>/oauth (jeder Port).