# DOGFATHER UNIVERSE — Interner Bereich (Cloudflare Worker + D1) Setzt das Anforderungsdokument **„Geschützter Zugang, Rollen und Benutzerverwaltung"** (`Geschuetzter_Zugang_Rollen_Benutzerverwaltung.pdf`) vollständig um: Session-basierte Anmeldung, verschlüsselte (aber für Dogi jederzeit einsehbare) Zugangscodes, frei konfigurierbare Rollen mit granularen Rechten, individuelle Ausnahmen pro Person, Aktivitätsprotokoll, Login-Lockout. Kosten: läuft im kostenlosen Cloudflare-Tier (Workers Free, D1 Free, KV Free reichen locker). ## ✅ Bereits deployed - **Interner Worker:** https://dogfather-universe-postfach.dogfather1608.workers.dev (Health-Check: `/health`) - **D1-Datenbank:** `dogfather-universe-db` - Website (`postfach.html`, `zugaenge.html`, `assets/js/*.js`) zeigt bereits auf diese URL. Die Schritte unten sind nur nötig, falls der Worker mal neu aufgesetzt werden muss. ## Architektur ``` src/worker.js Router — verteilt Requests an die Handler unten src/lib/crypto.js SHA-256-Hashing, AES-256-GCM-Verschlüsselung, ID/Token-Erzeugung src/lib/auth.js Login-Prüfung, Sessions, Rate-Limiting/Lockout src/lib/permissions.js Vollständiger Permission-Katalog aus dem Anforderungsdokument src/lib/audit.js Aktivitätsprotokoll schreiben (nie mit Codes!) src/lib/http.js CORS/JSON-Helfer src/routes/auth.js Login/Logout src/routes/users.js Zugänge und Teammitglieder (inkl. Code-Funktionen, NUR Owner) src/routes/roles.js Rollen erstellen/umbenennen/löschen src/routes/applications.js Bewerbungen: Status, Zuweisung, Notizen, Antwortentwürfe src/routes/audit.js Aktivitätsprotokoll auslesen migrations/0001_init.sql D1-Schema (users, roles, sessions, audit_log, applications, ...) ``` ## Das Kernprinzip (aus dem Anforderungsdokument) > Nur der Hauptadministrator sieht jederzeit alle vollständigen Zugangscodes und nur der > Hauptadministrator darf sie erstellen, ändern, kopieren, zurücksetzen oder sperren. Technisch umgesetzt: - **Owner-Code** = das `POSTFACH_CODE`-Secret. Kein Datenbankeintrag, kann nicht gelöscht/verändert werden außer von Dogi selbst per `wrangler secret put`. - **Team-Codes** werden **zweifach** gespeichert: - `code_hash` (SHA-256, nicht umkehrbar) — für den schnellen Login-Vergleich. - `code_enc` (AES-256-GCM, umkehrbar) — nur damit kann der Owner sich den Klartext-Code später wieder anzeigen lassen. Der Schlüssel dafür liegt ausschließlich im `ENCRYPTION_KEY`-Secret. - **Code anzeigen** verlangt zusätzlich eine Re-Authentifizierung (Owner-Code erneut eingeben), bevor der Klartext entschlüsselt und zurückgegeben wird. - Folgende Aktionen sind **fest an `isOwner === true` gebunden** und erscheinen nirgends als wählbare Berechtigung: Code anzeigen/kopieren/erstellen/ändern/zurücksetzen, den eigenen Owner-Zugang bearbeiten, die Owner-Rolle löschen/einschränken, jemanden zum Owner machen. ## Voraussetzungen - Ein (kostenloser) Cloudflare-Account - Node.js installiert (für `npx wrangler`) ## Deploy von Grund auf (falls je nötig) Alles im Ordner `cloudflare-worker/` ausführen: ```bash cd cloudflare-worker # 1. Bei Cloudflare einloggen npx wrangler login # 2. D1-Datenbank anlegen npx wrangler d1 create dogfather-universe-db # -> "database_id" aus der Ausgabe in wrangler.toml eintragen # 3. Schema anlegen npx wrangler d1 execute dogfather-universe-db --remote --file=migrations/0001_init.sql # 4. KV-Namespace anlegen (nur noch für den Live-Status-Schalter genutzt) npx wrangler kv namespace create BEWERBUNGEN # -> "id" aus der Ausgabe in wrangler.toml eintragen # 5. Owner-Code festlegen (dein persönlicher Hauptadministrator-Zugang) npx wrangler secret put POSTFACH_CODE # 6. Verschlüsselungs-Schlüssel für Team-Codes festlegen (32 zufällige Bytes, base64) # z.B. erzeugen mit: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" npx wrangler secret put ENCRYPTION_KEY # 7. (Optional) Bewerbungen zusätzlich automatisch in Discord posten — # siehe Abschnitt "Bewerbungen auf Discord (Ticketanizer)" unten. # Ohne diesen Schritt läuft alles wie gehabt, es fehlt nur die # Discord-Benachrichtigung. # 8. Deployen npx wrangler deploy ``` ## Bewerbungen auf Discord (Ticketanizer) Jede eingehende Bewerbung wird zusätzlich zur Speicherung in der Datenbank als schön formatierte Nachricht (Embed) in den passenden Discord-Kanal gepostet — pro Bewerbungsbereich ein eigener Kanal/Webhook, exakt wie auf der Website getrennt (Modi, Scout, Creator, Kooperation). **Das läuft komplett über normale Discord-Webhooks — kein Bot, kein zusätzlicher Code auf Discord-Seite nötig.** Falls Ticketanizer selbst in seinen Board-/Kanal-Einstellungen bereits eine eigene Ziel-Webhook-URL anzeigt, kann diese genauso eingetragen werden wie eine normale Discord-Webhook-URL — beide funktionieren identisch (Discord-Webhook-Format). ### Einrichtung (pro Kanal ca. 1 Minute) 1. Im Discord-Kanal (z.B. dem Modi-Bewerbungskanal): Kanal bearbeiten → **Integrationen** → **Webhooks** → **Neuer Webhook**. 2. Der Webhook kann beliebig heißen (z.B. "Homepage-Bewerbungen"). **Webhook-URL kopieren.** 3. Als Secret im Worker hinterlegen (einmal pro Bewerbungsbereich, nur die URLs eintragen, die schon vorhanden sind — fehlende werden einfach übersprungen, es gibt dafür keine Fehlermeldung): ```bash npx wrangler secret put DISCORD_WEBHOOK_MODI npx wrangler secret put DISCORD_WEBHOOK_SCOUT npx wrangler secret put DISCORD_WEBHOOK_CREATOR npx wrangler secret put DISCORD_WEBHOOK_KOOPERATION ``` Jeweils die kopierte Webhook-URL einfügen, wenn danach gefragt wird. 4. Danach einmal `npx wrangler deploy`, damit der Worker die neuen Secrets kennt (Secrets selbst brauchen keinen Deploy, aber schadet nicht). ### Wichtig - **Discord ist rein informativ, kein Ausfallpunkt.** Fehlt eine Webhook-URL oder ist Discord kurz nicht erreichbar, wird die Bewerbung trotzdem ganz normal in der Datenbank gespeichert — nur die Zusatz-Nachricht in Discord entfällt dann. - Secrets stehen **nie** im Code oder in `wrangler.toml` (die ist eingecheckt), sondern ausschließlich verschlüsselt bei Cloudflare — genau wie `POSTFACH_CODE` und `ENCRYPTION_KEY`. - Ändern/Ersetzen einer URL: den jeweiligen `wrangler secret put ...`-Befehl erneut ausführen, überschreibt den alten Wert. ## Wer den Owner-Code kennen darf Nur du. Er ist dein Hauptadministrator-Zugang — sieht ausnahmslos alles, kann Zugänge/Rollen/Codes verwalten. Ändern: `wrangler secret put POSTFACH_CODE` erneut ausführen. ## Zugänge und Teammitglieder verwalten Auf `zugaenge.html` (verlinkt von `postfach.html`, wenn du als Owner eingeloggt bist): - **Neue Zugänge erstellen** — Name, Benutzername, E-Mail, Rolle, Gültigkeit, Notiz. Code manuell festlegen oder automatisch sicher generieren lassen. Wird **einmalig** im Klartext angezeigt — danach nur noch über „Code anzeigen" (mit Re-Auth) abrufbar. - **Rollen frei erstellen** — jedes einzelne Recht per Checkbox an-/abschaltbar (Bewerbungsbereiche, Bearbeitung, Antworten, Notizen, Teamverwaltung, Einstellungen). Die Code-Funktionen tauchen dort bewusst nirgends auf. - **Individuelle Ausnahmen pro Person** — zusätzlich zur Rolle einzelne Rechte gezielt erlauben oder entziehen. - **Delegierbare Teilfunktion:** Personen mit dem Recht „Neue Benutzer vorbereiten" können einen Entwurf anlegen (Name, Benutzername, Rolle) — der Zugang bleibt inaktiv, bis du ihn im Bereich „Zugänge" mit „Freigeben & Code erstellen" final aktivierst. - **Pro Person:** Code anzeigen/kopieren/neu erstellen (nur Owner), Sperren/Entsperren, alle Sitzungen beenden (nur Owner), Rolle ändern, Rechte verwalten, vollständig löschen (nur Owner). ## Sicherheitsmaßnahmen - Nach 5 falschen Codes pro Client 15 Minuten Sperre (`login_attempts`-Tabelle). - Sessions: 30 Minuten Inaktivitäts-Timeout, 12 Stunden absolute Höchstdauer. - Zugangscodes erscheinen **niemals** im Aktivitätsprotokoll, im Quelltext oder in Fehlermeldungen. - CORS ist aktuell offen (`*`) — sobald die finale Domain feststeht, in `src/lib/http.js` → `corsHeaders()` auf die echte Domain einschränken. ## Wartung - Bewerbungen/Zugänge/Rollen: alles über `zugaenge.html` bzw. `postfach.html` als Owner. - Direktzugriff auf die Datenbank bei Bedarf: `npx wrangler d1 execute dogfather-universe-db --remote --command="SELECT ..."`