Verwaltungs-Code statt Tages-Code: Begriff klargestellt (Code ist fest, nur Sitzung läuft täglich ab)

Der Name "Tages-Code" konnte fälschlich als sich täglich änderndem/rotierendem Code
verstanden werden. Tatsächlich bleibt der Code dauerhaft gleich (6GAM4AST) — nur die
24h-Sitzung läuft ab, wodurch derselbe Code einmal pro Tag erneut eingegeben werden
muss. Reine Text-/Kommentar-Korrektur, keine Verhaltensänderung.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-04 11:54:56 +02:00
co-authored by Claude Sonnet 5
parent aff961816b
commit b70bad3e41
5 changed files with 33 additions and 23 deletions
+11 -8
View File
@@ -32,9 +32,10 @@
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 einen zweiten, eigenen Tages-Code (siehe functions/_shared/verwaltung-auth.js, noch einen zweiten, eigenen, FESTEN Code (siehe functions/_shared/verwaltung-auth.js,
/verwaltung-code.html) — auf ausdrücklichen Wunsch, damit die Bestellübersicht auch bei /verwaltung-code.html) — auf ausdrücklichen Wunsch. Der Code selbst ändert sich NICHT von
einer kompromittierten/geteilten normalen Sitzung nicht dauerhaft offen bleibt. selbst (kein Zufalls-/Rotationscode) — nur die SITZUNG läuft nach 24 Stunden ab, wodurch
derselbe Code einmal täglich neu eingegeben werden muss, statt für immer gültig 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.
@@ -108,9 +109,11 @@ 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 Tages-Code — /* Gegenstück zu handleAuth() oben, aber für den zweiten, verwaltungseigenen Code — bewusst EIN
bewusst EIN gemeinsamer Code (kein Unterschied qciga/VanVan), da es hier nur um die gemeinsamer, FESTER Code (kein Unterschied qciga/VanVan, keine Rotation), da es hier nur um
zusätzliche Hürde geht, nicht um eine rollenabhängige Anzeige. */ die zusätzliche Hürde geht, nicht um eine rollenabhängige Anzeige. Nur die dadurch erzeugte
SITZUNG läuft nach 24h ab (siehe VERWALTUNG_SESSION_STUNDEN unten) — der Code selbst bleibt
unverändert, bis ihn qciga manuell über "wrangler pages secret put" ändert. */
async function handleVerwaltungAuth(request, env) { async function handleVerwaltungAuth(request, env) {
let body; let body;
try { try {
@@ -125,7 +128,7 @@ async function handleVerwaltungAuth(request, env) {
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) { if (!env.VERWALTUNG_ACCESS_CODE || code !== env.VERWALTUNG_ACCESS_CODE) {
return new Response(JSON.stringify({ ok: false, error: "Falscher Tages-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" },
}); });
@@ -217,7 +220,7 @@ export async function onRequest(context) {
} }
if (url.pathname.startsWith("/api/")) { if (url.pathname.startsWith("/api/")) {
return new Response(JSON.stringify({ ok: false, error: "Tages-Code für die Verwaltung erforderlich." }), { return new Response(JSON.stringify({ ok: false, error: "Zusätzlicher Verwaltungs-Code erforderlich." }), {
status: 401, status: 401,
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
+10 -4
View File
@@ -1,9 +1,15 @@
/* ===================================================================== /* =====================================================================
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/* — auf ausdrücklichen Wunsch: ein einziger, gemeinsamer,
Tages-Code, den nur qciga und VanVan kennen, unabhängig vom normalen 90-Tage-Seitenzugang FESTER Code (VERWALTUNG_ACCESS_CODE), den nur qciga und VanVan kennen, unabhängig vom
(siehe functions/_shared/auth.js). Wer die Bestellübersicht öffnen will, braucht also BEIDE normalen 90-Tage-Seitenzugang (siehe functions/_shared/auth.js). Wer die Bestellübersicht
Codes — den normalen Seitenzugang UND diesen hier, und dieser hier läuft nach 24 Stunden ab. öffnen will, braucht also BEIDE Codes — den normalen Seitenzugang UND diesen hier.
WICHTIG: Der Code selbst ändert sich NIE von selbst (kein Zufalls-/Rotationscode, keine
Tages-Ableitung) — nur die durch ihn erzeugte SITZUNG läuft nach 24 Stunden ab. Dadurch
muss derselbe, unveränderte Code einmal täglich neu eingegeben werden, statt dauerhaft
gültig zu bleiben (auf ausdrücklichen Wunsch: "ein fester Code, der aber jeden Tag einmal
eingegeben werden 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
+4 -3
View File
@@ -5,8 +5,9 @@
Zusätzlich zur Middleware (functions/_middleware.js, schützt /api/verwaltung/* IMMER, Zusätzlich zur Middleware (functions/_middleware.js, schützt /api/verwaltung/* IMMER,
unabhängig von SITE_PUBLIC) prüft diese Route die Sitzung noch einmal selbst — Verteidigung unabhängig von SITE_PUBLIC) prüft diese Route die Sitzung noch einmal selbst — Verteidigung
in der Tiefe, falls diese Datei mal unabhängig von der Middleware aufgerufen wird. Das in der Tiefe, falls diese Datei mal unabhängig von der Middleware aufgerufen wird. Das
umfasst BEIDE Schranken: den normalen Seitenzugang UND den zusätzlichen Verwaltungs- umfasst BEIDE Schranken: den normalen Seitenzugang UND den zusätzlichen Verwaltungs-Code
Tages-Code (siehe functions/_shared/verwaltung-auth.js). ===================================================================== */ (fest, tägliche Neueingabe wegen Sitzungsablauf — siehe functions/_shared/verwaltung-auth.js).
===================================================================== */
import { getGateRole, unauthorizedJson } from "../../_shared/auth.js"; import { getGateRole, unauthorizedJson } from "../../_shared/auth.js";
import { hatGueltigeVerwaltungSitzung } from "../../_shared/verwaltung-auth.js"; import { hatGueltigeVerwaltungSitzung } from "../../_shared/verwaltung-auth.js";
@@ -18,7 +19,7 @@ export async function onRequestGet(context) {
const role = await getGateRole(request, env); const role = await getGateRole(request, env);
if (!role) return unauthorizedJson(); if (!role) return unauthorizedJson();
if (!(await hatGueltigeVerwaltungSitzung(request, env))) { if (!(await hatGueltigeVerwaltungSitzung(request, env))) {
return json(401, { ok: false, error: "Tages-Code für die Verwaltung erforderlich." }); return json(401, { ok: false, error: "Zusätzlicher Verwaltungs-Code erforderlich." });
} }
if (!env.DB) { if (!env.DB) {
+2 -2
View File
@@ -4,7 +4,7 @@
Genau wie bei GET /api/verwaltung/orders: zusätzlich zur Middleware-Sperre wird die Genau wie bei GET /api/verwaltung/orders: zusätzlich zur Middleware-Sperre wird die
Sitzung hier noch einmal eigenständig geprüft — beide Schranken (normaler Seitenzugang UND Sitzung hier noch einmal eigenständig geprüft — beide Schranken (normaler Seitenzugang UND
Verwaltungs-Tages-Code). ===================================================================== */ Verwaltungs-Code, fest, tägliche Neueingabe wegen Sitzungsablauf). ===================================================================== */
import { getGateRole, unauthorizedJson } from "../../../_shared/auth.js"; import { getGateRole, unauthorizedJson } from "../../../_shared/auth.js";
import { hatGueltigeVerwaltungSitzung } from "../../../_shared/verwaltung-auth.js"; import { hatGueltigeVerwaltungSitzung } from "../../../_shared/verwaltung-auth.js";
@@ -18,7 +18,7 @@ export async function onRequestPatch(context) {
const role = await getGateRole(request, env); const role = await getGateRole(request, env);
if (!role) return unauthorizedJson(); if (!role) return unauthorizedJson();
if (!(await hatGueltigeVerwaltungSitzung(request, env))) { if (!(await hatGueltigeVerwaltungSitzung(request, env))) {
return json(401, { ok: false, error: "Tages-Code für die Verwaltung erforderlich." }); return json(401, { ok: false, error: "Zusätzlicher Verwaltungs-Code erforderlich." });
} }
if (!env.DB) { if (!env.DB) {
+6 -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>Tages-Code — Bestellverwaltung</title> <title>Verwaltungs-Code — 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>
@@ -128,12 +128,12 @@
</head> </head>
<body> <body>
<div class="gate-box"> <div class="gate-box">
<span class="gate-eyebrow">🔒 Tages-Code</span> <span class="gate-eyebrow">🔒 Zusätzlicher Code</span>
<h1>Bestellverwaltung</h1> <h1>Bestellverwaltung</h1>
<p>Diese Seite ist zusätzlich mit einem eigenen Code geschützt, den nur ihr beide kennt — <p>Diese Seite ist zusätzlich mit einem eigenen, festen Code geschützt, den nur ihr beide
er muss einmal pro Tag neu eingegeben werden.</p> kennt. Der Code bleibt immer gleich — ihr müsst ihn aber einmal pro Tag neu eingeben.</p>
<form id="vw-form"> <form id="vw-form">
<input type="text" id="vw-code" placeholder="Tages-Code" autocomplete="off" autocapitalize="off" spellcheck="false" autofocus /> <input type="text" id="vw-code" placeholder="Verwaltungs-Code" autocomplete="off" autocapitalize="off" spellcheck="false" autofocus />
<button type="submit">Weiter</button> <button type="submit">Weiter</button>
</form> </form>
<p class="gate-fehler" id="vw-fehler"></p> <p class="gate-fehler" id="vw-fehler"></p>
@@ -158,7 +158,7 @@
}); });
const data = await res.json(); const data = await res.json();
if (!res.ok || !data.ok) { if (!res.ok || !data.ok) {
fehlerEl.textContent = (data && data.error) || "Falscher Tages-Code."; fehlerEl.textContent = (data && data.error) || "Falscher Code.";
fehlerEl.classList.add("zeige"); fehlerEl.classList.add("zeige");
return; return;
} }