/* ===================================================================== webdesign-ausweis.js — Ausweis der Zugangswand anerkennen Hintergrund (Rückmeldung 22.08.2026: "ich will es nur einmal eingeben müssen"): Die Zugangswand vor /webdesign hat serverseitig bereits geprüft, wer da ist. Dogfather und VanVan sind laut Masterplan S.4 gleichberechtigte Volladministratoren. Ein zweites Passwort für die Verwaltung bringt danach keinen zusätzlichen Schutz — es kostet nur jedes Mal Zeit. Der Ausweis wird von server/webdesign-gate.js ausgestellt und hier geprüft. Beide Seiten teilen sich dafür WEBDESIGN_API_SECRET. ⚠️ WAS DIESER AUSWEIS NICHT IST Er ist KEIN Team-Login. Er berechtigt ausschließlich zu den Webdesign-Endpunkten und verschafft keinerlei Zugriff auf Postfach, Bewerbungen, Supporter oder Teamverwaltung. Wer den Webdesign-Bereich betreten darf, darf damit nicht automatisch alles andere auch. ⚠️ FEHLT DAS GEHEIMNIS, GILT KEIN AUSWEIS Dann bleibt es bei der Team-Anmeldung wie bisher. Ein fehlender Konfigurationswert darf niemals eine Tür öffnen — nur eine schließen. ===================================================================== */ import { createHmac, timingSafeEqual } from "node:crypto"; function b64urlZurueck(str) { return Buffer.from(String(str).replace(/-/g, "+").replace(/_/g, "/"), "base64"); } /** * Prüft den Ausweis aus dem Authorization-Kopf. * Liefert { rolle } bei Gültigkeit, sonst null. */ export function ausweisPruefen(req) { const geheim = process.env.WEBDESIGN_API_SECRET; if (!geheim) return null; // nicht eingerichtet -> kein Ausweis const kopf = req.headers["authorization"] || ""; const token = kopf.startsWith("Bearer ") ? kopf.slice(7) : null; if (!token || !token.includes(".")) return null; const [nutzlast, sigB64] = token.split("."); try { const erwartet = createHmac("sha256", geheim).update(nutzlast).digest(); const geliefert = b64urlZurueck(sigB64); /* Länge zuerst vergleichen: timingSafeEqual wirft bei unterschiedlich langen Puffern, statt false zu liefern. */ if (geliefert.length !== erwartet.length) return null; if (!timingSafeEqual(geliefert, erwartet)) return null; const daten = JSON.parse(b64urlZurueck(nutzlast).toString("utf8")); /* bereich prüfen: Ohne diesen Vergleich würde ein Sitzungs-Token der öffentlichen Zugangswand hier ebenfalls durchgehen, obwohl es für einen ganz anderen Zweck ausgestellt wurde. */ if (daten.bereich !== "wd-admin") return null; if (!daten.exp || daten.exp < Date.now()) return null; if (daten.rolle !== "dogfather" && daten.rolle !== "vanvan") return null; return { rolle: daten.rolle }; } catch { return null; } } /** * Einheitliche Rechteprüfung für die Webdesign-Endpunkte. * * Zwei Wege führen hinein: * 1. Der Ausweis der Zugangswand (Dogfather oder VanVan) — beide sind * Volladministratoren und dürfen im Webdesign-Bereich alles. * 2. Eine normale Team-Anmeldung mit dem passenden Einzelrecht — für * den Fall, dass später jemand aus dem Team nur Anfragen ansehen, * aber keine Kundendaten bearbeiten soll. * * `pruefeTeam` wird als Funktion hereingereicht, damit diese Datei nichts * von auth.js und permissions.js wissen muss. */ export async function darfWebdesign(req, recht, pruefeTeam) { const ausweis = ausweisPruefen(req); if (ausweis) return { erlaubt: true, actor: ausweis.rolle, ueberAusweis: true }; return pruefeTeam(); }