diff --git a/functions/_middleware.js b/functions/_middleware.js index 30d4e29..1ca61ad 100644 --- a/functions/_middleware.js +++ b/functions/_middleware.js @@ -42,6 +42,29 @@ import { COOKIE_NAME, ROLE_COOKIE_NAME, SESSION_TAGE, signSession, verifySession, getCookie } from "./_shared/auth.js"; +/* Seiten, die auch ohne Zugangscode ausgeliefert werden (siehe Begründung unten in onRequest). + Bewusst als feste, vollständige Liste statt "alles was mit X anfängt" — so kann hier nicht + versehentlich mehr freigegeben werden als gewollt. */ +const OEFFENTLICHE_SEITEN = new Set([ + "/impressum", + "/datenschutz", + "/agb", + "/widerruf", + "/muster-widerrufsformular", +]); + +/* Damit diese Seiten nicht nackt/ohne Gestaltung beim Prüfteam ankommen, sind zusätzlich die + rein gestalterischen Dateien freigegeben: Stylesheets sowie Logo/Favicons. Bewusst NUR + .css aus /_astro/ — die JavaScript-Bündel dort enthalten u.a. Produktdaten und bleiben + deshalb weiterhin hinter der Schranke. */ +function istOeffentlichErreichbar(pfad) { + const ohneSlash = pfad.endsWith("/") && pfad.length > 1 ? pfad.slice(0, -1) : pfad; + if (OEFFENTLICHE_SEITEN.has(ohneSlash)) return true; + if (pfad.startsWith("/_astro/") && pfad.endsWith(".css")) return true; + if (/^\/(logo\.png|favicon\.ico|favicon-\d+x\d+\.png|apple-touch-icon\.png|icon-\d+(-maskable)?\.png)$/.test(pfad)) return true; + return false; +} + async function handleAuth(request, env) { let body; try { @@ -89,6 +112,17 @@ export async function onRequest(context) { return next(); } + // Rechtstexte (Impressum, Datenschutz, AGB, Widerruf) bleiben IMMER ohne Zugangscode + // erreichbar. Grund: PayPal prüft vor der Freischaltung von "Log in with PayPal" die + // angegebene Datenschutz- und AGB-Adresse tatsächlich nach — hinter der Zugangsschranke + // sähe deren Prüfteam nur die Code-Eingabe, und die Freischaltung würde scheitern. Gleiches + // gilt für Google (verlangt beim Veröffentlichen eine erreichbare Datenschutzerklärung). + // Rechtlich ist das ohnehin die saubere Seite: Impressum und Datenschutzerklärung sollen + // "ständig verfügbar" sein. Diese Seiten enthalten keine Shop-/Kundendaten. + if (istOeffentlichErreichbar(url.pathname)) { + return next(); + } + // Fail-open-Absicherung: fehlen die Zugangs-Secrets komplett (z.B. noch nicht gesetzt), lieber // GAR KEINE Schranke scharf schalten, als sich selbst aus der eigenen Seite auszusperren. const codesKonfiguriert = !!(env.SITE_ACCESS_SECRET && (env.SITE_ACCESS_CODE_QCIGA || env.SITE_ACCESS_CODE_VANVAN));