# ADR-0005: Zugangsdaten kommen aus der App, nicht aus der `.env` **Status:** akzeptiert · **Datum:** 2026-09-09 ## Kontext Das Toolkit braucht Client-ID und Client-Secret zweier Twitch-Apps, ein obs-websocket-Passwort und später Discord-/Bluesky-Zugänge. Der erste Entwurf sah dafür eine `.env`-Datei vor, die von Hand befüllt wird. Das passt nicht zum Nutzer. Abdu ist Streamer, kein Entwickler. „Kopiere `.env.example` nach `.env` und trage sieben Werte ein" ist die Stelle, an der ein Werkzeug liegen bleibt. Und es kommt ein zweites Problem dazu, das für diesen Anwendungsfall besonders zählt: **Wer eine Klartextdatei mit Zugangsdaten öffnet, während er sendet, hat sie live gezeigt.** ## Entscheidung Zugangsdaten werden über einen **Einrichtungs-Assistenten im Browser** eingegeben, unter `http://localhost:4792/setup`. Gespeichert werden sie verschlüsselt in `/db/secrets.json` im Docker-Volume. Die `.env` bleibt bestehen, enthält aber nur noch **optionale** Werte (Log-Level, Pfad zum Wiedergabepuffer). Ohne `.env` startet alles. Damit fällt auch Port 4780 weg: Einrichtung, OAuth-Rücksprung und später Sichtungsseite und Dashboard laufen über **einen** Server auf Port 4792. Die Redirect-URI in der Twitch-App lautet entsprechend `http://localhost:4792/callback`. ## Speicherung | | | |---|---| | Ort | `/db/secrets.json`, benanntes Volume `abdulive-db` | | Verfahren | AES-256-GCM, Schlüssel in `/db/.secret-key` (Modus 0600) | | Schlüssel | wird beim ersten Start erzeugt, nie ausgegeben, nie geloggt | | **Nicht** in SQLite | damit das Backup-Skript sie nie mitkopiert | Die Secrets liegen bewusst **außerhalb der Datenbank**. `scripts/backup.ps1` zieht die `.db` aus dem Volume nach `data/db/backup/` — also auf die Windows-Seite, wo sie in einer Cloud-Synchronisation landen kann. Was dort nichts zu suchen hat, darf gar nicht erst in der Datenbank stehen. ## Was diese Verschlüsselung leistet — und was nicht Der Schlüssel liegt im selben Volume wie die verschlüsselten Daten. Gegen jemanden, der Zugriff auf das Volume hat, schützt das **nicht**, und es wird hier auch nicht so getan. Wogegen es schützt, und das ist der eigentliche Zweck: - **Versehentliche Anzeige im Stream.** `cat secrets.json` zeigt Kauderwelsch, keine Client-Secrets. - **Verirrte Kopien.** Ein Volume-Export oder ein weitergegebener Ordner enthält ohne die Schlüsseldatei nichts Verwertbares. - **Grep-Unfälle.** Secrets tauchen in keiner Volltextsuche und in keinem versehentlich geteilten Log auf. Gegen eine Kompromittierung der Maschine schützt es nicht. Das ist bei einem lokalen Einzelplatzwerkzeug auch nicht das Bedrohungsmodell — wer dort Zugriff hat, hat auch Zugriff auf OBS, den Browser und die gespeicherten Twitch-Cookies. ## Konsequenzen für die Oberfläche - Der Einrichtungs-Assistent **zeigt gespeicherte Secrets nie wieder an.** Nach dem Speichern steht dort `•••••• gespeichert` und ein Knopf *Ersetzen*. - Über der Seite steht ein Hinweis: **„Diese Seite zeigt Zugangsdaten — nicht im Stream öffnen."** - Der Server ist nur lokal erreichbar. **Nicht** dadurch, dass er im Container auf `127.0.0.1` bindet — das wäre dort die Container-Loopback, die Dockers Portweiterleitung nie erreicht, der Dienst wäre schlicht tot. Die Abschottung kommt aus zwei Teilen: der Container bindet auf `0.0.0.0` **innerhalb seines eigenen Netzwerk-Namensraums**, und Compose veröffentlicht den Port ausschließlich als `127.0.0.1:4792`. Außerhalb von Docker bindet der Server weiterhin auf die Loopback-Adresse; gesteuert über `BIND_HOST`, das nur das Image auf `0.0.0.0` setzt. - Secrets werden nie geloggt, auch nicht bei Fehlern. Der Logger maskiert bekannte Schlüsselnamen. - `check-env` meldet, *ob* Zugangsdaten hinterlegt sind, nie *welche*. ## Preis Der Einrichtungs-Assistent kostet in S1 ungefähr einen zusätzlichen Tag — kleiner HTTP-Server, eine Seite, der Secret-Speicher. Dafür entfällt der gesamte `.env`-Schritt aus der Inbetriebnahme, und das Werkzeug lässt sich später ohne Texteditor umkonfigurieren.