Verwaltung: nur noch EINMAL den Code eingeben

Rueckmeldung 22.08.2026: "ich hab auf der verwaltungs seite 2 mal dass ich
den zugangscode eingeben muss und vanvan auch, ich will es nur einmal
eingeben muessen." Berechtigt.

Die Zugangswand hat serverseitig laengst geprueft, WER da ist -- Dogfather
oder VanVan, laut Masterplan S.4 beide gleichberechtigte
Volladministratoren. Ein zweites Passwort danach bringt keinen
zusaetzlichen Schutz, es kostet nur jedes Mal Zeit.

Warum es nicht einfach "Cookie mitschicken" ist: Die Verwaltungsdaten
liegen hinter postfach.dogfather-universe.com, einem ANDEREN Rechnernamen.
Das Sitzungs-Cookie gilt dort nicht -- so sind Cookies gebaut, und das ist
gut so.

Loesung: Die Zugangswand stellt unter /webdesign/api-ausweis einen
kurzlebigen, signierten Ausweis aus, den die interne API anerkennt.
  - 15 Minuten gueltig, die Seite holt bei Bedarf still einen neuen
  - traegt bereich="wd-admin", damit ein Sitzungs-Token der Zugangswand
    hier NICHT durchgeht und umgekehrt
  - nur mit gueltiger Zugangssitzung zu bekommen
  - gilt AUSSCHLIESSLICH fuer die /webdesign-Endpunkte. Postfach,
    Bewerbungen, Supporter und Teamverwaltung bleiben unberuehrt

Fehlt WEBDESIGN_API_SECRET auf einer der beiden Seiten, gilt kein Ausweis
und die Verwaltung fragt wie bisher nach dem Team-Code. Ein fehlender
Konfigurationswert darf niemals eine Tuer oeffnen -- nur eine schliessen.
Genau das prueft der letzte Testfall.

Bei einem 401 wird EINMAL still ein neuer Ausweis geholt und die Anfrage
wiederholt, statt jemanden mitten im Arbeiten rauszuwerfen.

10/10 Tests, darunter: gefaelschte Signatur, fremdes Geheimnis,
abgelaufen, falscher Bereich, erfundene Rolle.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-22 21:36:11 +02:00
co-authored by Claude Opus 5
parent 2542a2598e
commit 74091590b8
8 changed files with 298 additions and 9 deletions
+60 -9
View File
@@ -160,8 +160,10 @@
<div id="vw-anmeldung" class="wd-karte vw-login" hidden>
<h1 style="font-size:1.4rem">Verwaltung</h1>
<p class="wd-klein wd-leise">
Dein persönlicher Zugangscode aus dem internen Bereich — derselbe
wie für das Postfach. Der Code der Zugangswand gilt hier nicht.
Normalerweise landest du hier gar nicht: Wer durch die Zugangswand
gekommen ist, wird direkt hereingelassen. Diese Maske erscheint nur,
wenn das nicht möglich war — dann brauchst du deinen persönlichen
Zugangscode aus dem internen Bereich (derselbe wie fürs Postfach).
</p>
<form id="vw-login-form" novalidate>
<div class="wd-feld" id="vw-feld-code">
@@ -385,8 +387,20 @@
window.WD.meldungAus(meldung);
} catch (fehler) {
if (fehler.status === 401) {
/* Sitzung abgelaufen — zurück zur Anmeldung statt einer
Fehlermeldung, mit der niemand etwas anfangen kann. */
/* Der Ausweis der Zugangswand laeuft nach 15 Minuten ab. Statt
jemanden mitten im Arbeiten rauszuwerfen, EINMAL still einen
neuen holen und es nochmal versuchen. Klappt auch das nicht,
ist die Zugangssitzung selbst weg -- dann zurueck zur
Anmeldung, nicht zu einer leeren Liste. */
if (!ausweisVersucht) {
ausweisVersucht = true;
var frisch = await ausweisHolen();
if (frisch) {
token = frisch; tokenSchreiben(token);
ausweisVersucht = false;
return ladeAnfragen();
}
}
token = null; tokenSchreiben(null); zeigeAnmeldung();
return;
}
@@ -814,12 +828,49 @@
}
}
/* ---------------- Start ---------------- */
function start() {
/* ---------------- Start ----------------
Reihenfolge bewusst so:
1. Ein bereits geholter Ausweis im Sitzungsspeicher.
2. Sonst: einen neuen bei der Zugangswand holen. Die hat serverseitig
laengst geprueft, wer hier ist -- ein zweites Passwort danach
bringt keinen zusaetzlichen Schutz und kostet nur Zeit
(Rueckmeldung 22.08.2026).
3. Erst wenn das nicht klappt (Ausweis nicht eingerichtet, Sitzung
abgelaufen), die eigene Anmeldemaske.
Der Ausweis laeuft nach 15 Minuten ab. Deshalb wird bei jedem 401
einmal stillschweigend ein neuer geholt und die Anfrage wiederholt --
sonst fliegt man mitten im Arbeiten raus. */
var ausweisVersucht = false;
async function ausweisHolen() {
try {
var antwort = await fetch("/webdesign/api-ausweis", { cache: "no-store" });
if (!antwort.ok) return null;
var daten = await antwort.json();
return daten && daten.ausweis ? daten.ausweis : null;
} catch (e) {
return null;
}
}
async function start() {
token = tokenLesen();
if (!token) { zeigeAnmeldung(); return; }
zeigeBereich();
ladeAnfragen();
if (token) { zeigeBereich(); ladeAnfragen(); return; }
var ausweis = await ausweisHolen();
if (ausweis) {
token = ausweis;
tokenSchreiben(token);
document.getElementById("vw-name").textContent =
(document.cookie.match(/dogiwd_rolle=([^;]+)/) || [])[1] === "vanvan" ? "VanVan" : "Dogfather";
zeigeBereich();
ladeAnfragen();
return;
}
zeigeAnmeldung();
}
if (window.WD) start();