Verwaltungsseite: kein separater dritter Code mehr, sondern derselbe wie beim normalen Login

Fix für gemeldetes Problem: VanVans Code funktionierte nicht auf der Verwaltungsseite. Ursache
war ein dritter, komplett separater, gemeinsamer Code (6GAM4AST), den sich niemand gemerkt
hatte — VanVan gab stattdessen ihren normalen persönlichen Zugangscode ein, der dort aber nicht
galt. Jetzt auf ausdrücklichen Wunsch vereinheitlicht: die Verwaltungsseite prüft denselben
persönlichen Code wie der normale Seitenzugang (SITE_ACCESS_CODE_QCIGA/_VANVAN). Die tägliche
Neueingabe-Pflicht bleibt bestehen (eigene Sitzung mit 24h statt 90 Tagen Gültigkeit) — nur der
geprüfte Code ist jetzt kein separater dritter mehr. Das alte Secret VERWALTUNG_ACCESS_CODE wird
nicht mehr verwendet. Lokal mit wrangler pages dev end-to-end getestet (beide Codes + alter Code
korrekt abgelehnt).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-04 12:54:01 +02:00
co-authored by Claude Sonnet 5
parent 850aed2f9e
commit c1504bef92
3 changed files with 46 additions and 35 deletions
+25 -15
View File
@@ -31,11 +31,13 @@
ist nie für Kund:innen gedacht. /api/orders (Bestellung ANLEGEN beim Checkout) ist bewusst ist nie für Kund:innen gedacht. /api/orders (Bestellung ANLEGEN beim Checkout) ist bewusst
NICHT dauerhaft geschützt — das muss auch für echte Kund:innen erreichbar sein, sobald der NICHT dauerhaft geschützt — das muss auch für echte Kund:innen erreichbar sein, sobald der
Shop öffentlich ist, genau wie der Checkout selbst. Shop öffentlich ist, genau wie der Checkout selbst.
- /verwaltung/* + /api/verwaltung/* verlangen ZUSÄTZLICH zum normalen 90-Tage-Seitenzugang - /verwaltung/* + /api/verwaltung/* verlangen ZUSÄTZLICH zum normalen 90-Tage-Seitenzugang noch
noch einen zweiten, eigenen, FESTEN Code (siehe functions/_shared/verwaltung-auth.js, eine zweite, eigene Sitzung, die nur 24 Stunden gültig ist (siehe
/verwaltung-code.html) — auf ausdrücklichen Wunsch. Der Code selbst ändert sich NICHT von functions/_shared/verwaltung-auth.js, /verwaltung-code.html) — auf ausdrücklichen Wunsch.
selbst (kein Zufalls-/Rotationscode) — nur die SITZUNG läuft nach 24 Stunden ab, wodurch Geprüft wird dabei GENAU DERSELBE persönliche Code wie beim normalen Seitenzugang (kein
derselbe Code einmal täglich neu eingegeben werden muss, statt für immer gültig zu bleiben. separater dritter Code mehr — das hatte anfangs zu Verwirrung geführt, siehe Tagesprotokoll
04.08.2026). Wer /verwaltung/ öffnen will, tippt also überall denselben Code, muss ihn aber
hier einmal täglich neu eingeben, statt 90 Tage lang eingeloggt zu bleiben.
- API-Routen (/api/*) bekommen bei fehlender Sitzung eine 401-JSON-Antwort statt der - API-Routen (/api/*) bekommen bei fehlender Sitzung eine 401-JSON-Antwort statt der
302-Weiterleitung zur Zugangscode-Seite — ein fetch() im Checkout/Verwaltung-Skript soll 302-Weiterleitung zur Zugangscode-Seite — ein fetch() im Checkout/Verwaltung-Skript soll
einen klaren Fehler sehen, nicht versehentlich HTML als Antwort bekommen. einen klaren Fehler sehen, nicht versehentlich HTML als Antwort bekommen.
@@ -109,11 +111,14 @@ async function handleAuth(request, env) {
return new Response(JSON.stringify({ ok: true, next }), { status: 200, headers }); return new Response(JSON.stringify({ ok: true, next }), { status: 200, headers });
} }
/* Gegenstück zu handleAuth() oben, aber für den zweiten, verwaltungseigenen Code — bewusst EIN /* Gegenstück zu handleAuth() oben, aber für die zweite, tägliche Sitzung auf /verwaltung/ — auf
gemeinsamer, FESTER Code (kein Unterschied qciga/VanVan, keine Rotation), da es hier nur um ausdrücklichen Wunsch NACH einer Verwirrung mit einem anfangs dritten, separaten Code umgestellt
die zusätzliche Hürde geht, nicht um eine rollenabhängige Anzeige. Nur die dadurch erzeugte (04.08.2026): Es gibt KEINEN eigenen Verwaltungs-Code mehr. Stattdessen gilt hier genau derselbe
SITZUNG läuft nach 24h ab (siehe VERWALTUNG_SESSION_STUNDEN unten) — der Code selbst bleibt persönliche Code wie beim normalen Seitenzugang (SITE_ACCESS_CODE_QCIGA / SITE_ACCESS_CODE_VANVAN,
unverändert, bis ihn qciga manuell über "wrangler pages secret put" ändert. */ siehe handleAuth() oben) — wer sich einmal am Tag einloggt, tippt also überall denselben, ihr
bereits bekannten Code, statt sich einen dritten, separaten Code merken zu müssen. Einzige
Besonderheit gegenüber dem normalen Zugang: die dadurch erzeugte SITZUNG läuft schon nach 24h ab
(statt 90 Tage), wodurch derselbe Code hier täglich neu eingegeben werden muss. */
async function handleVerwaltungAuth(request, env) { async function handleVerwaltungAuth(request, env) {
let body; let body;
try { try {
@@ -127,7 +132,10 @@ async function handleVerwaltungAuth(request, env) {
const code = (body.code || "").trim(); const code = (body.code || "").trim();
const next = typeof body.next === "string" && body.next.startsWith("/") ? body.next : "/verwaltung/"; const next = typeof body.next === "string" && body.next.startsWith("/") ? body.next : "/verwaltung/";
if (!env.VERWALTUNG_ACCESS_CODE || code !== env.VERWALTUNG_ACCESS_CODE) { const codeGueltig =
(env.SITE_ACCESS_CODE_QCIGA && code === env.SITE_ACCESS_CODE_QCIGA) ||
(env.SITE_ACCESS_CODE_VANVAN && code === env.SITE_ACCESS_CODE_VANVAN);
if (!codeGueltig) {
return new Response(JSON.stringify({ ok: false, error: "Falscher Code." }), { return new Response(JSON.stringify({ ok: false, error: "Falscher Code." }), {
status: 401, status: 401,
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
@@ -206,10 +214,12 @@ export async function onRequest(context) {
return handleVerwaltungAuth(request, env); return handleVerwaltungAuth(request, env);
} }
// Fail-open auch hier: fehlt das Secret komplett, lieber die zweite Schranke nicht scharf // Fail-open auch hier: fehlt das Sitzungs-Secret komplett, lieber die zweite Schranke nicht
// schalten, als sich selbst auszusperren — die erste Schranke (normaler Seitenzugang) // scharf schalten, als sich selbst auszusperren — die erste Schranke (normaler Seitenzugang)
// schützt /verwaltung/ in diesem Fall ja immer noch. // schützt /verwaltung/ in diesem Fall ja immer noch. Die Zugangscodes selbst
if (!env.VERWALTUNG_SESSION_SECRET || !env.VERWALTUNG_ACCESS_CODE) { // (SITE_ACCESS_CODE_QCIGA/_VANVAN) sind an dieser Stelle bereits garantiert vorhanden, siehe
// codesKonfiguriert-Prüfung weiter oben in onRequest().
if (!env.VERWALTUNG_SESSION_SECRET) {
return next(); return next();
} }
+14 -14
View File
@@ -1,22 +1,22 @@
/* ===================================================================== /* =====================================================================
functions/_shared/verwaltung-auth.js — ZWEITE, ZUSÄTZLICHE Zugangsschranke NUR für functions/_shared/verwaltung-auth.js — ZWEITE, ZUSÄTZLICHE Zugangsschranke NUR für
/verwaltung/ + /api/verwaltung/* — auf ausdrücklichen Wunsch: ein einziger, gemeinsamer, /verwaltung/ + /api/verwaltung/*, unabhängig vom normalen 90-Tage-Seitenzugang (siehe
FESTER Code (VERWALTUNG_ACCESS_CODE), den nur qciga und VanVan kennen, unabhängig vom functions/_shared/auth.js). Wer die Bestellübersicht öffnen will, braucht also eine gültige
normalen 90-Tage-Seitenzugang (siehe functions/_shared/auth.js). Wer die Bestellübersicht Sitzung auf BEIDEN Ebenen — die Prüfung des eingegebenen Codes selbst läuft dabei nicht hier,
öffnen will, braucht also BEIDE Codes — den normalen Seitenzugang UND diesen hier. sondern in handleVerwaltungAuth() in functions/_middleware.js (dort wird GENAU DERSELBE
persönliche Code wie beim normalen Seitenzugang akzeptiert, SITE_ACCESS_CODE_QCIGA/_VANVAN —
WICHTIG: Der Code selbst ändert sich NIE von selbst (kein Zufalls-/Rotationscode, keine ursprünglich gab es hier einen dritten, separaten Code, der aber auf ausdrücklichen Wunsch
Tages-Ableitung) — nur die durch ihn erzeugte SITZUNG läuft nach 24 Stunden ab. Dadurch nach echter Verwirrung bei VanVan am 04.08.2026 wieder entfernt wurde). Diese Datei kümmert
muss derselbe, unveränderte Code einmal täglich neu eingegeben werden, statt dauerhaft sich nur noch um die SITZUNG danach: die läuft absichtlich schon nach 24 Stunden ab (statt
gültig zu bleiben (auf ausdrücklichen Wunsch: "ein fester Code, der aber jeden Tag einmal 90 Tage wie beim normalen Zugang), wodurch derselbe Code hier täglich neu eingegeben werden
eingegeben werden muss"). muss.
Bewusst als eigene, kleine Kopie der HMAC-Signaturlogik statt geteiltem Code mit auth.js Bewusst als eigene, kleine Kopie der HMAC-Signaturlogik statt geteiltem Code mit auth.js
(gleiches Prinzip wie bei customer-auth.js) — ein Leck bei einer Sitzungsart darf nie die (gleiches Prinzip wie bei customer-auth.js) — ein Leck bei einer Sitzungsart darf nie die
andere gefährden. Eigenes Geheimnis (VERWALTUNG_SESSION_SECRET), eigenes Cookie, eigener andere gefährden. Eigenes Geheimnis (VERWALTUNG_SESSION_SECRET), eigenes Cookie — auch wenn
einzelner Code (VERWALTUNG_ACCESS_CODE) statt getrennter Codes pro Person — hier reicht ein der geprüfte CODE jetzt derselbe wie beim normalen Zugang ist, bleibt die SITZUNG technisch
gemeinsamer Code, weil es nur um diese eine zusätzliche Hürde geht, nicht um die Anzeige komplett getrennt (anderes Cookie, andere Gültigkeitsdauer, eigene Signatur).
einer rollenabhängigen Vorschau wie beim normalen Seitenzugang. ===================================================================== */ ===================================================================== */
export const VERWALTUNG_COOKIE_NAME = "vandiy_verwaltung_session"; export const VERWALTUNG_COOKIE_NAME = "vandiy_verwaltung_session";
export const VERWALTUNG_SESSION_STUNDEN = 24; export const VERWALTUNG_SESSION_STUNDEN = 24;
+7 -6
View File
@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Verwaltungs-Code — Bestellverwaltung</title> <title>Tägliche Bestätigung — Bestellverwaltung</title>
<meta name="robots" content="noindex, nofollow" /> <meta name="robots" content="noindex, nofollow" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<style> <style>
@@ -253,14 +253,15 @@
<span class="vw-sparkle vw-sparkle-2">💛</span> <span class="vw-sparkle vw-sparkle-2">💛</span>
<span class="vw-sparkle vw-sparkle-3">🧶</span> <span class="vw-sparkle vw-sparkle-3">🧶</span>
</div> </div>
<span class="gate-eyebrow">🔒 Zusätzlicher Code</span> <span class="gate-eyebrow">🔒 Tägliche Bestätigung</span>
<h1>Bestellverwaltung</h1> <h1>Bestellverwaltung</h1>
<p class="vw-welcome">🌟 Schön, dass du da bist!</p> <p class="vw-welcome">🌟 Schön, dass du da bist!</p>
<p>Diese Seite ist zusätzlich mit einem eigenen, festen Code geschützt, den nur ihr beide <p>Diese Seite braucht einmal pro Tag eine erneute Bestätigung mit deinem <strong>ganz normalen,
kennt. Der Code bleibt immer gleich — ihr müsst ihn aber einmal pro Tag neu eingeben.</p> persönlichen Zugangscode</strong> — demselben, den du auch für die Startseite benutzt. Es ist
kein neuer oder anderer Code.</p>
<form id="vw-form"> <form id="vw-form">
<label class="sr-only" for="vw-code">Verwaltungs-Code</label> <label class="sr-only" for="vw-code">Dein persönlicher Zugangscode</label>
<input type="text" id="vw-code" placeholder="Verwaltungs-Code" autocomplete="off" autocapitalize="off" spellcheck="false" autofocus /> <input type="text" id="vw-code" placeholder="Dein Zugangscode" autocomplete="off" autocapitalize="off" spellcheck="false" autofocus />
<button type="submit">✨ Los geht's</button> <button type="submit">✨ Los geht's</button>
</form> </form>
<p class="gate-fehler" id="vw-fehler" role="alert" aria-live="assertive"></p> <p class="gate-fehler" id="vw-fehler" role="alert" aria-live="assertive"></p>