From 718b267de0cf76f47bb467eec21bc87016d53b94 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Thu, 1 Oct 2026 00:22:55 +0200 Subject: [PATCH] Zugang: die gewaehlte Kachel ist bindend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filipe, 01.10.2026: „mach das. es soll fest sein." VanVan hatte gemeldet: „Man kann sich mit seinem Zugangscode immer noch über jeden Button der Startseite anmelden, egal welche Rolle man hat." ICH HATTE ZUERST ABGERATEN -- und lag falsch, weil ich eine alte Lage beschrieben habe. Am 09.09.2026 hatte Filipe entschieden, dass die Modis KEINE eigene Eingangskachel bekommen: „damit die von der workspace auch nicht mal sehen dass die modis von mir einen eigenen zugang haben." Wer keine Kachel hat, muss irgendeine nehmen koennen -- daher der stille Zugang. SEIT DER HAUSTRENNUNG AM 24.09.2026 STIMMT DAS NICHT MEHR. Auf `crew.` steht laengst ein eigener Kachelsatz mit ALLEN fuenf Rollen: DogFather, rechte Hand, linke Hand, Modi, Community (CREW_KACHEL, und crew-index.html zeigt sie). Das Verbergen leistet seither die ADRESSE -- wer sie nicht kennt, findet die Wand nicht; wer sie kennt, liest die Rollennamen ohnehin offen darauf. Der stille Zugang war damit ein Rest. Er hat niemanden mehr geschuetzt und nur dafuer gesorgt, dass die Kachelwahl folgenlos blieb. Nachgesehen habe ich das erst, NACHDEM Filipe widersprochen hat; die Kachelsaetze standen die ganze Zeit im Quelltext. WAS SICH NICHT AENDERT: Auf der Agenturwand war der stille Zugang nie aktiv. Ein Team-Dogi-Code verhaelt sich dort weiterhin wie ein erfundener -- gleiche Antwort, gleicher Weg, gleiche Dauer. Das ist jetzt ausdruecklich gemessen. EINE PRUEFADRESSE IST KEINE WAND. `127.0.0.1` ist weder crew. noch Agentur. Ohne den stillen Zugang gaelte dort der Agentursatz -- und kein Modi kaeme mehr herein. Fuenfzig Pruefdateien melden Team-Rollen ueber diese Adresse an. Auf einer Adresse ohne Wand gibt es deshalb ALLE Kacheln; welche auf welcher ECHTEN Wand steht, misst pruef-modi-verborgen mit ausdruecklichem Host-Kopf. GEPRUEFT -- pruef-modi-verborgen 87/0 (war 85; die fuenf Zeilen „jede Kachel geht" sind durch sieben ersetzt, die die neue Regel und ihre Gegenproben messen). Die Anzahl ist Zeile fuer Zeile verglichen. Modi-Kachel + Modi-Code -> herein admin/hand/linke/gast -> abgewiesen rechte Hand auf ihrer Kachel -> herein Agenturwand + Modi-Code -> wie ein erfundener pruef-crew-adresse 169/0 (unveraenderte Anzahl, zwei Zeilen umgedreht). SECHZEHN PRUEFDATEIEN MELDETEN SICH UEBER FREMDE KACHELN AN -- ein Rest derselben Zeit. Systematisch gesucht statt einzeln entdeckt: Waere ich dem roten Lauf hinterhergelaufen, haette ich beim zwoelften aufgehoert. UND DABEI EIN EIGENER FEHLER: Mein erster Durchlauf las die Rolle am CODENAMEN ab (CODE-MODI- -> modi). Das ging gut, bis „Nane" kam: ein Modi mit dem Code CODE-NANE-0001. Zwei Pruefungen wurden rot, und zwar an einer Stelle („die Stimmen stimmen"), die mit Anmeldung nichts zu tun hat. Ein Codename ist eine Beschriftung, keine Tatsache -- die Rolle steht in `anlegen()`. Danach abgeleitet blieben genau zwei Abweichungen uebrig, und beide sind absichtliche Gegenproben. Drei Browserpruefungen tippten die Creator-Kachel mit einem Modi-Code. Die Modi-Kachel gibt es nur auf der Crew-Wand, und ein Browser auf 127.0.0.1 bekommt die Agenturwand; sie melden sich jetzt ueber die Schnittstelle an und bekommen den Keks. Gemessen werden soll dort, was ein Modi SIEHT -- nicht, wie er hereinkommt. Grün: pruef-modi-verborgen, pruef-crew-adresse, pruef-treff 85/0, pruef-galerie, pruef-kanaele, pruef-modi-katalog 150/0, pruef-modi-ideen, pruef-modi-kategorien, pruef-modi-checkliste 75/0, pruef-modi-livecheck, pruef-kachelraster, pruef-team-ampel 32/0, pruef-team-stufen 47/0, pruef-wunschliste, pruef-bremse, pruef-gespraech, pruef-personen-formular 43/0, pruef-start-ansicht, pruef-community-sicht, pruef-reaktion 421/0, pruef-abzeichen, pruef-chat, pruef-chat-kanaele 81/0, pruef-entwicklung 79/0, pruef-bewerbung-aufgaben 154/0, pruef-struktur, pruef-zwischenspeicher 34/0. `code_kennung` wird weiter geschrieben, aber nicht mehr gelesen -- sie war der Suchschluessel des stillen Weges. Stehen gelassen: Eine Spalte zu entfernen ist eine Schemaaenderung mit Sicherung, und sie kostet nichts. Co-Authored-By: Claude Opus 5 --- server/pruef-bremse.mjs | 2 +- server/pruef-crew-adresse.mjs | 26 +++- server/pruef-galerie.mjs | 2 +- server/pruef-gespraech.mjs | 2 +- server/pruef-kachelraster.mjs | 6 +- server/pruef-kanaele.mjs | 4 +- server/pruef-kreislauf.mjs | 2 +- server/pruef-modi-checkliste.mjs | 2 +- server/pruef-modi-ideen.mjs | 26 ++-- server/pruef-modi-katalog.mjs | 28 +++-- server/pruef-modi-kategorien.mjs | 58 +++++++-- server/pruef-modi-livecheck.mjs | 2 +- server/pruef-modi-verborgen.mjs | 200 +++++++++++++++++++++++++------ server/pruef-team-ampel.mjs | 2 +- server/pruef-team-stufen.mjs | 4 +- server/pruef-treff.mjs | 7 +- server/pruef-wunschliste.mjs | 6 +- server/workspace.js | 161 ++++++++----------------- workspace/anruf-probe.html | 10 +- workspace/app.webmanifest | 8 +- workspace/aufgaben.html | 38 +++--- workspace/automation.html | 32 ++--- workspace/befinden.html | 34 +++--- workspace/bereich.html | 44 +++---- workspace/bewerben.html | 38 +++--- workspace/bewerbungen.html | 36 +++--- workspace/buehne.html | 6 +- workspace/calls.html | 34 +++--- workspace/chat.html | 40 +++---- workspace/content.html | 34 +++--- workspace/crew-index.html | 12 +- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 34 +++--- workspace/entwicklung.html | 36 +++--- workspace/hilfe.html | 30 ++--- workspace/index.html | 10 +- workspace/kalender.html | 34 +++--- workspace/leistung.html | 32 ++--- workspace/material.html | 32 ++--- workspace/notizen.html | 28 ++--- workspace/personen.html | 32 ++--- workspace/profil.html | 36 +++--- workspace/reaktion.html | 38 +++--- workspace/rechte.html | 34 +++--- workspace/report.html | 36 +++--- workspace/scouting.html | 32 ++--- workspace/start.html | 32 ++--- workspace/startcheck.html | 34 +++--- workspace/steckbrief.html | 36 +++--- workspace/support.html | 28 ++--- workspace/tafel.html | 6 +- workspace/talente.html | 36 +++--- workspace/team.html | 32 ++--- workspace/teamlage.html | 34 +++--- workspace/teilen.html | 30 ++--- workspace/treff-moderation.html | 32 ++--- workspace/treff-regeln.html | 32 ++--- workspace/uebersicht.html | 32 ++--- workspace/unsere-seiten.html | 30 ++--- workspace/unterstuetzen.html | 32 ++--- workspace/werdegang.html | 32 ++--- workspace/willkommen.html | 30 ++--- workspace/wissen.html | 34 +++--- 63 files changed, 1017 insertions(+), 863 deletions(-) diff --git a/server/pruef-bremse.mjs b/server/pruef-bremse.mjs index 0e12b898..11b8d49e 100644 --- a/server/pruef-bremse.mjs +++ b/server/pruef-bremse.mjs @@ -107,7 +107,7 @@ async function anmelden(kachel, code) { return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); } const dogi = await anmelden("admin", "CODE-DOGI-0001"); -const ruhig = await anmelden("creator", "CODE-RUHIG-0001"); +const ruhig = await anmelden("modi", "CODE-RUHIG-0001"); const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS }); async function schreiben(keks, bereich, titel, extra = {}) { diff --git a/server/pruef-crew-adresse.mjs b/server/pruef-crew-adresse.mjs index 6f8cfbf1..22115439 100644 --- a/server/pruef-crew-adresse.mjs +++ b/server/pruef-crew-adresse.mjs @@ -201,11 +201,20 @@ try { zielModi = JSON.parse(modiAufCrew.text); } catch { /* bleibt leer */ } ok(zielModi.weiter === "/workspace/start.html", "crew.: er landet auf seiner Startseite"); ok(modiAufCrew.keks.includes("dfw_sitzung"), "crew.: er bekommt eine Sitzung"); -/* Der Code des Modis wird bewusst mit der Kachel 'creator' geschickt -- - genau so kommt er auch aus der Zugangswand, denn eine Modi-Kachel - gibt es nicht. */ -const modiOhneKachel = await anmelden(CREW, "creator", "CODE-MODI-0001"); -ok(modiOhneKachel.status === 200, "crew.: die gewaehlte Kachel ist egal (stiller Zugang)"); +/* ==== DIE KACHEL IST BINDEND (01.10.2026) ========================= + + Filipe: „mach das. es soll fest sein." + + Hier stand das Gegenteil, und es war richtig: Bis zum 24.09.2026 + gab es fuer einen Modi keine eigene Kachel, also musste jede + durchgehen (Filipes Entscheidung vom 09.09.). + + Seit der Haustrennung hat `crew.` einen eigenen Kachelsatz mit + allen fuenf Rollen. Das Verbergen leistet seither die ADRESSE -- + der Trick mit der beliebigen Kachel war ein Rest. */ +const modiFremdeKachel = await anmelden(CREW, "creator", "CODE-MODI-0001"); +ok(modiFremdeKachel.status === 401, + `crew.: eine fremde Kachel wird abgewiesen (${modiFremdeKachel.status})`); const managerAufCrew = await anmelden(CREW, "manager", "CODE-MAN-0001"); ok(managerAufCrew.status === 401, "crew.: ein Manager mit gueltigem Code kommt NICHT herein"); @@ -262,7 +271,12 @@ ok(managerAufWs.status === 200 && managerAufWs.keks.includes("dfw_sitzung"), "workspace.: der Manager kommt herein wie immer -- der Workspace ist unberuehrt"); const managerLokal = await anmelden(LOKAL, "manager", "CODE-MAN-0001"); -const modiLokal = await anmelden(LOKAL, "creator", "CODE-MODI-0001"); +/* AUF SEINER EIGENEN KACHEL. Eine Pruefadresse ist keine Wand -- + dort gibt es seit dem 01.10.2026 ALLE Kacheln, damit die fuenfzig + Pruefdateien, die Team-Rollen ueber 127.0.0.1 anmelden, weiter + messen koennen. Welche Kachel auf welcher ECHTEN Wand steht, sagt + die Zeile weiter oben. */ +const modiLokal = await anmelden(LOKAL, "modi", "CODE-MODI-0001"); ok(managerLokal.status === 200 && managerLokal.keks.includes("dfw_sitzung"), "127.0.0.1: der Manager kommt herein (Pruefadressen unberuehrt)"); ok(modiLokal.status === 200 && modiLokal.keks.includes("dfw_sitzung"), diff --git a/server/pruef-galerie.mjs b/server/pruef-galerie.mjs index a0dfff9c..9dce9c8a 100644 --- a/server/pruef-galerie.mjs +++ b/server/pruef-galerie.mjs @@ -99,7 +99,7 @@ async function anmelden(kachel, code) { return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); } const dogi = await anmelden("admin", "CODE-DOGI-0001"); -const modi = await anmelden("creator", "CODE-MODI-0001"); +const modi = await anmelden("modi", "CODE-MODI-0001"); /* ---------- Ein Highlight und die Dateien dazu ----------------------- */ const a = await fetch(BASIS + "/workspace/api/bereich/highlight", { diff --git a/server/pruef-gespraech.mjs b/server/pruef-gespraech.mjs index 40fbdf99..a909cda4 100644 --- a/server/pruef-gespraech.mjs +++ b/server/pruef-gespraech.mjs @@ -89,7 +89,7 @@ async function anmelden(kachel, code) { return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); } const dogi = await anmelden("admin", "CODE-DOGI-0001"); -const lena = await anmelden("creator", "CODE-LENA-0001"); +const lena = await anmelden("modi", "CODE-LENA-0001"); const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS }); async function liste(bereich, keks = dogi) { diff --git a/server/pruef-kachelraster.mjs b/server/pruef-kachelraster.mjs index 44f60d6b..dca66f8f 100644 --- a/server/pruef-kachelraster.mjs +++ b/server/pruef-kachelraster.mjs @@ -317,7 +317,9 @@ try { melde(""); melde("=== 2. Ein Modi: dasselbe Raster ==="); { - const m = await messen("creator", "CODE-MODI-0001", "modi"); + /* AUF DER MODI-KACHEL (01.10.2026) -- vorher liess der stille + Zugang jede durch. */ + const m = await messen("modi", "CODE-MODI-0001", "modi"); /* ACHT, NICHT SIEBEN -- und das war MEIN Denkfehler beim Schreiben dieser Pruefung, nicht der des Codes: Ein Modi moderiert, also braucht er "Meldungen & Massnahmen". Die Liste im Quelltext sagt @@ -405,7 +407,7 @@ try { darin. Genommen wird der Modi -- er ist die Rolle in dieser Pruefung, die eine Kachel mit `gross: true` hat, und nur an der kann der Fehler ueberhaupt auftreten. */ - const keksBreite = await anmelden("creator", "CODE-MODI-0001"); + const keksBreite = await anmelden("modi", "CODE-MODI-0001"); for (const breite of [320, 360, 390]) { const k2 = await browser.newContext({ diff --git a/server/pruef-kanaele.mjs b/server/pruef-kanaele.mjs index 7bdce2b5..0ad91b18 100644 --- a/server/pruef-kanaele.mjs +++ b/server/pruef-kanaele.mjs @@ -111,8 +111,8 @@ async function ruf(keks, pfad, aufruf = {}) { const jsonKopf = { "Content-Type": "application/json" }; const dogi = await anmelden("admin", "CODE-DOGI-0001"); -const hand = await anmelden("creator", "CODE-HAND-0001"); -const modi = await anmelden("creator", "CODE-MODI-0001"); +const hand = await anmelden("hand", "CODE-HAND-0001"); +const modi = await anmelden("modi", "CODE-MODI-0001"); const crea = await anmelden("creator", "CODE-CREA-0001"); /* ======================================================================= diff --git a/server/pruef-kreislauf.mjs b/server/pruef-kreislauf.mjs index bb29e8a6..4de97b99 100644 --- a/server/pruef-kreislauf.mjs +++ b/server/pruef-kreislauf.mjs @@ -97,7 +97,7 @@ async function anmelden(kachel, code) { return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); } const dogi = await anmelden("admin", "CODE-DOGI-0001"); -const lena = await anmelden("creator", "CODE-LENA-0001"); +const lena = await anmelden("modi", "CODE-LENA-0001"); const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS }); async function liste(bereich, keks = dogi) { diff --git a/server/pruef-modi-checkliste.mjs b/server/pruef-modi-checkliste.mjs index ee8e6c88..427323d0 100644 --- a/server/pruef-modi-checkliste.mjs +++ b/server/pruef-modi-checkliste.mjs @@ -100,7 +100,7 @@ async function hole(keks, pfad, aufruf = {}) { } const jsonKopf = { "Content-Type": "application/json" }; -const modiAn = await anmelden("creator", "CODE-MODI-0001"); +const modiAn = await anmelden("modi", "CODE-MODI-0001"); const dogiAn = await anmelden("admin", "CODE-DOGI-0001"); const vanAn = await anmelden("admin", "CODE-VAN-0001"); const handAn = await anmelden("hand", "CODE-HAND-0001"); diff --git a/server/pruef-modi-ideen.mjs b/server/pruef-modi-ideen.mjs index 0dbb5ac1..d3dc9744 100644 --- a/server/pruef-modi-ideen.mjs +++ b/server/pruef-modi-ideen.mjs @@ -174,8 +174,8 @@ const jsonKopf = { "Content-Type": "application/json" }; /* ---------- 3. Sammeln und priorisieren ------------------------------ */ console.log("\n=== 3. Ideen sammeln und nach Dringlichkeit ordnen ===\n"); -const modiAn = await anmelden("creator", "CODE-MODI-0001"); -const modi2An = await anmelden("creator", "CODE-MODI-0002"); +const modiAn = await anmelden("modi", "CODE-MODI-0001"); +const modi2An = await anmelden("modi", "CODE-MODI-0002"); const dogiAn = await anmelden("admin", "CODE-DOGI-0001"); { const IDEEN = [ @@ -297,11 +297,23 @@ console.log("\n=== 5. Das Board im echten Browser ===\n"); schlecht.push(`${r.status()} ${r.url().replace(BASIS, "")}`); } }); - await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" }); - await seite.click('.rolle[data-rolle="creator"]'); - await seite.fill("#code", "CODE-MODI-0001"); - await seite.click("button[type=submit]"); - await seite.waitForURL("**/start.html", { timeout: 15000 }); + /* ==== ANGEMELDET UEBER DEN KEKS (01.10.2026) ================ + + Hier wurde auf die Creator-Kachel getippt und ein Modi-Code + eingegeben -- das ging, solange der stille Zugang jede Kachel + durchliess. Seit die Kachel bindend ist, braeuchte der Browser + die MODI-Kachel, und die gibt es nur auf der Crew-Wand; ein + Browser auf 127.0.0.1 bekommt die Agenturwand. + + Gemessen werden soll hier, was ein Modi SIEHT -- nicht, wie er + hereinkommt. Das steht in pruef-modi-verborgen, und dort wird es + an der echten Wand gemessen. */ + const modiKeks = String((await anmelden("modi", "CODE-MODI-0001")).keks || ""); + await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => { + const [n2, ...r2] = z.split("="); + return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" }; + })); + await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" }); /* WARTEN, BIS DIE KACHELN DA SIND. Sie entstehen erst, wenn /api/ich geantwortet hat -- direkt nach waitForURL ist die Seite zwar geladen, aber leer. Beim ersten Anlauf meldete diese diff --git a/server/pruef-modi-katalog.mjs b/server/pruef-modi-katalog.mjs index 2a1439c5..5425679d 100644 --- a/server/pruef-modi-katalog.mjs +++ b/server/pruef-modi-katalog.mjs @@ -104,14 +104,14 @@ async function hole(keks, pfad, aufruf = {}) { } const jsonKopf = { "Content-Type": "application/json" }; -const modiAn = await anmelden("creator", "CODE-MODI-0001"); +const modiAn = await anmelden("modi", "CODE-MODI-0001"); const dogiAn = await anmelden("admin", "CODE-DOGI-0001"); const manAn = await anmelden("manager", "CODE-MAN-0001"); const creatAn = await anmelden("creator", "CODE-ANNA-0001"); /* Ueber den stillen Zugang -- welche Kachel man anfasst, ist gleichgueltig, der Code allein entscheidet (siehe die Anmelderoute). */ -const handAn = await anmelden("creator", "CODE-HAND-0001"); -const linkeAn = await anmelden("creator", "CODE-LINK-0001"); +const handAn = await anmelden("hand", "CODE-HAND-0001"); +const linkeAn = await anmelden("linke", "CODE-LINK-0001"); /* ---------- 1. Ist er vollstaendig da? ------------------------------- */ console.log("\n=== 1. Der Katalog, wie ihn das Dokument beschreibt ===\n"); @@ -493,11 +493,23 @@ console.log("\n=== 6. Das Brett im echten Browser ===\n"); const konsole = []; seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); }); seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message)); - await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" }); - await seite.click('.rolle[data-rolle="creator"]'); - await seite.fill("#code", "CODE-MODI-0001"); - await seite.click("button[type=submit]"); - await seite.waitForURL("**/start.html", { timeout: 15000 }); + /* ==== ANGEMELDET UEBER DEN KEKS (01.10.2026) ================ + + Hier wurde auf die Creator-Kachel getippt und ein Modi-Code + eingegeben -- das ging, solange der stille Zugang jede Kachel + durchliess. Seit die Kachel bindend ist, braeuchte der Browser + die MODI-Kachel, und die gibt es nur auf der Crew-Wand; ein + Browser auf 127.0.0.1 bekommt die Agenturwand. + + Gemessen werden soll hier, was ein Modi SIEHT -- nicht, wie er + hereinkommt. Das steht in pruef-modi-verborgen, und dort wird es + an der echten Wand gemessen. */ + const modiKeks = String((await anmelden("modi", "CODE-MODI-0001")).keks || ""); + await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => { + const [n2, ...r2] = z.split("="); + return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" }; + })); + await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" }); /* DER KATALOG STEHT SEIT DEM 23.09.2026 AUF "EURE AUFGABEN". Filipe: "das soll auch bitte nicht in der kategorie aufgaben sondern eure aufgaben sein bitte." */ diff --git a/server/pruef-modi-kategorien.mjs b/server/pruef-modi-kategorien.mjs index 51bc514a..d3062e94 100644 --- a/server/pruef-modi-kategorien.mjs +++ b/server/pruef-modi-kategorien.mjs @@ -104,7 +104,7 @@ async function hole(keks, pfad, aufruf = {}) { /* ---------- 1. Wer bekommt die Liste ueberhaupt? --------------------- */ console.log("\n=== 1. Wer bekommt die Kategorien zu sehen? ===\n"); -const modiAn = await anmelden("creator", "CODE-MODI-0001"); +const modiAn = await anmelden("modi", "CODE-MODI-0001"); const dogiAn = await anmelden("admin", "CODE-DOGI-0001"); const manAn = await anmelden("manager", "CODE-MAN-0001"); const creatAn = await anmelden("creator", "CODE-ANNA-0001"); @@ -255,10 +255,33 @@ console.log("\n=== 5. Das Feld im echten Formular ===\n"); s.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); }); s.on("pageerror", (e) => konsole.push("Absturz: " + e.message)); await s.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" }); - await s.click(`.rolle[data-rolle="${kachel}"]`); - await s.fill("#code", code); - await s.click("button[type=submit]"); - await s.waitForURL("**/start.html", { timeout: 15000 }); + /* ==== GIBT ES DIESE KACHEL AUF DIESER WAND? (01.10.2026) ==== + + Seit die Kachel bindend ist, muss jeder auf SEINER anmelden. + Die Modi-Kachel steht aber nur auf der Crew-Wand, und ein + Browser auf 127.0.0.1 bekommt die Agenturwand -- dort gibt + es sie nicht. + + Also wird gefragt statt angenommen: Ist die Kachel da, wird + getippt wie immer. Ist sie es nicht, geht die Anmeldung ueber + die Schnittstelle und der Keks wird mitgegeben. Gemessen + werden soll hier, was jemand SIEHT -- nicht, wie er + hereinkommt; das steht in pruef-modi-verborgen und wird dort + an der echten Wand gemessen. */ + const kachelDa = await s.$(`.rolle[data-rolle="${kachel}"]`); + if (kachelDa) { + await s.click(`.rolle[data-rolle="${kachel}"]`); + await s.fill("#code", code); + await s.click("button[type=submit]"); + await s.waitForURL("**/start.html", { timeout: 15000 }); + } else { + const keks = String((await anmelden(kachel, code)).keks || ""); + await k.addCookies(keks.split("; ").filter(Boolean).map((z) => { + const [n2, ...r2] = z.split("="); + return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" }; + })); + await s.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" }); + } await s.goto(BASIS + "/workspace/aufgaben.html", { waitUntil: "networkidle" }); await s.waitForTimeout(900); await s.click("#neu-oeffnen").catch(() => {}); @@ -268,7 +291,8 @@ console.log("\n=== 5. Das Feld im echten Formular ===\n"); /* Der Modi: Feld da, Auswahl gefuellt. */ { - const { kontext, seite, konsole } = await formular("creator", "CODE-MODI-0001"); + /* AUF DER MODI-KACHEL, seit dem 01.10.2026 -- vorher ging jede. */ + const { kontext, seite, konsole } = await formular("modi", "CODE-MODI-0001"); const z = await seite.evaluate(() => { const h = document.getElementById("feld-kategorie"); const f = document.getElementById("f-kategorie"); @@ -421,11 +445,23 @@ console.log("\n=== 5. Das Feld im echten Formular ===\n"); { const kontext = await browser.newContext(); const seite = await kontext.newPage(); - await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" }); - await seite.click('.rolle[data-rolle="creator"]'); - await seite.fill("#code", "CODE-MODI-0001"); - await seite.click("button[type=submit]"); - await seite.waitForURL("**/start.html", { timeout: 15000 }); + /* ==== ANGEMELDET UEBER DEN KEKS (01.10.2026) ================ + + Hier wurde auf die Creator-Kachel getippt und ein Modi-Code + eingegeben -- das ging, solange der stille Zugang jede Kachel + durchliess. Seit die Kachel bindend ist, braeuchte der Browser + die MODI-Kachel, und die gibt es nur auf der Crew-Wand; ein + Browser auf 127.0.0.1 bekommt die Agenturwand. + + Gemessen werden soll hier, was ein Modi SIEHT -- nicht, wie er + hereinkommt. Das steht in pruef-modi-verborgen, und dort wird es + an der echten Wand gemessen. */ + const modiKeks = String((await anmelden("modi", "CODE-MODI-0001")).keks || ""); + await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => { + const [n2, ...r2] = z.split("="); + return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" }; + })); + await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" }); await seite.goto(BASIS + "/workspace/entwicklung.html", { waitUntil: "networkidle" }); await seite.waitForTimeout(1600); const text = await seite.evaluate(() => document.body.innerText); diff --git a/server/pruef-modi-livecheck.mjs b/server/pruef-modi-livecheck.mjs index 7a5b9dea..a724c85e 100644 --- a/server/pruef-modi-livecheck.mjs +++ b/server/pruef-modi-livecheck.mjs @@ -104,7 +104,7 @@ async function hole(keks, pfad, aufruf = {}) { const jsonKopf = { "Content-Type": "application/json" }; const dogiAn = await anmelden("admin", "CODE-DOGI-0001"); -const modiAn = await anmelden("creator", "CODE-MODI-0001"); +const modiAn = await anmelden("modi", "CODE-MODI-0001"); const manAn = await anmelden("manager", "CODE-MAN-0001"); /* ---------- Zwei Live-Termine mit dem Modi als Teilnehmer ----------- */ diff --git a/server/pruef-modi-verborgen.mjs b/server/pruef-modi-verborgen.mjs index 2b352215..8642b31f 100644 --- a/server/pruef-modi-verborgen.mjs +++ b/server/pruef-modi-verborgen.mjs @@ -111,40 +111,130 @@ d.close(); const MODIS = [idModi1, idModi2, idHand]; void idSpicy; -/* ---------- Anmelden ueber die Schnittstelle ------------------------- */ -async function anmelden(rolle, code) { - const a = await fetch(BASIS + "/workspace/api/anmelden", { - method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ rolle, code }), +/* ---------- Anmelden ueber die Schnittstelle ------------------------- + + MIT WAND, SEIT DEM 01.10.2026. Vorher ging jede Anmeldung hier ueber + `fetch` auf 127.0.0.1 -- eine Adresse OHNE Wand. Gemessen wurde + damit der stille Zugang und nicht die Kachelregel; seit er weg ist, + waere das die Messung der falschen Sache. + + WARUM node:http UND NICHT fetch: `fetch` (undici) setzt den + Host-Kopf selbst aus der Adresse und ignoriert einen mitgegebenen. + Nachgemessen, nicht vermutet -- dieselbe Stelle steht seit dem + 22.09. in pruef-chat-kanaele. */ +const { request: httpAnfrage } = await import("node:http"); +const CREW_WAND = "crew.dogfather-universe.com"; +const AGENTUR_WAND = "workspace.dogfather-universe.com"; + +/** Auf welcher Wand steht die Kachel dieser Rolle? + * + * ABGELEITET STATT AUFGEZAEHLT (01.10.2026). Nach dem Umbau meldeten + * sich acht Stellen ueber eine fremde Kachel an -- ein Manager auf + * der Crew-Wand etwa, wo es seine Kachel gar nicht gibt. Eine Liste + * von Hand waere die, bei der man zwei Stellen vergisst. + * + * Wer eine Wand AUSDRUECKLICH nennt, bekommt sie: Das brauchen die + * Zeilen, die absichtlich die falsche Wand pruefen. */ +const CREW_ROLLEN = new Set(["admin", "hand", "linke", "modi", "gast"]); +const wandFuer = (rolle) => (CREW_ROLLEN.has(rolle) ? CREW_WAND : AGENTUR_WAND); + +function anmelden(rolle, code, wand = wandFuer(rolle)) { + return new Promise((fertig) => { + const rumpf = JSON.stringify({ rolle, code }); + const a = httpAnfrage({ + host: "127.0.0.1", port: PORT, path: "/workspace/api/anmelden", method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": Buffer.byteLength(rumpf), + Host: wand, + }, + }, (antwort) => { + const teile = []; + antwort.on("data", (t) => teile.push(t)); + antwort.on("end", () => { + let daten = {}; + try { daten = JSON.parse(Buffer.concat(teile).toString("utf8")); } catch { /* kein JSON */ } + fertig({ + status: antwort.statusCode, + daten, + keks: [].concat(antwort.headers["set-cookie"] || []) + .map((z) => z.split(";")[0]).join("; "), + }); + }); + }); + a.on("error", () => fertig({ status: 0, daten: {}, keks: "" })); + a.end(rumpf); }); - const daten = await a.json().catch(() => ({})); - const keks = (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); - return { status: a.status, daten, keks }; } -console.log("\n=== 1. Der Eingang: eine Kachel gibt es nicht ===\n"); +/* ===================================================================== + 1. DIE KACHEL IST BINDEND (01.10.2026) -for (const kachel of ["creator", "scout", "manager", "spicy", "admin"]) { - const a = await anmelden(kachel, "CODE-MODI-0001"); - ok(a.status === 200 && a.daten?.rolle === "modi", - `Kachel "${kachel}" + Modi-Code -> angemeldet als ${a.daten?.rolle || a.status}`); -} + Filipe: „mach das. es soll fest sein." + + VanVan hatte gemeldet: „Man kann sich mit seinem Zugangscode immer + noch über jeden Button der Startseite anmelden, egal welche Rolle + man hat." + + BIS HEUTE STAND HIER DAS GEGENTEIL, und das war richtig: Vom + 09.09.2026 an hatten die Modis KEINE eigene Kachel -- wer keine + hat, muss irgendeine nehmen koennen. + + Seit der Haustrennung am 24.09. hat `crew.` einen eigenen + Kachelsatz mit allen fuenf Rollen. Das Verbergen leistet die + ADRESSE; der Trick mit der beliebigen Kachel war ein Rest. + ===================================================================== */ +console.log("\n=== 1. Der Eingang: die Kachel gilt ===\n"); -/* Der Umkehrschluss, und er ist der wichtigere: Der stille Weg darf - NICHT dazu fuehren, dass auch alle anderen die Kachel ignorieren - duerfen. Ein Manager mit der Kachel "creator" muss weiterhin - scheitern -- sonst haette ich nebenbei die Rollenpruefung - abgeschafft, ohne es zu merken. */ { - const a = await anmelden("creator", "CODE-MAN-0001"); + const a = await anmelden("modi", "CODE-MODI-0001"); + ok(a.status === 200 && a.daten?.rolle === "modi", + `auf der Modi-Kachel kommt ein Modi herein (${a.daten?.rolle || a.status})`); +} + +/* UND AUF KEINER ANDEREN. Das ist die Aenderung. */ +for (const kachel of ["admin", "hand", "linke", "gast"]) { + const a = await anmelden(kachel, "CODE-MODI-0001"); + ok(a.status === 401, + `Kachel "${kachel}" + Modi-Code -> abgewiesen (${a.status})`); +} + +/* GEGENPROBE: Die anderen Rollen der Crew-Wand kommen auf IHRER + Kachel herein. Ohne sie hiesse „401 ueberall" womoeglich nur, dass + dort gar niemand mehr hereinkommt. */ +{ + const h = await anmelden("hand", "CODE-HAND-0001"); + ok(h.status === 200 && h.daten?.rolle === "hand", + `die rechte Hand auf ihrer Kachel (${h.daten?.rolle || h.status})`); +} + +/* UND DIE AGENTURWAND BLEIBT, WIE SIE WAR. Dort war der stille Weg + nie aktiv; ein Modi-Code verhaelt sich weiter wie ein erfundener. */ +{ + const a = await anmelden("creator", "CODE-MODI-0001", AGENTUR_WAND); + const b = await anmelden("creator", "GIBT-ES-NICHT-1", AGENTUR_WAND); + ok(a.status === 401 && b.status === 401 + && JSON.stringify(a.daten) === JSON.stringify(b.daten), + `auf der Agenturwand klingt ein Modi-Code wie ein erfundener ` + + `(${a.status} vs. ${b.status})`); +} + +/* Und die Rollenpruefung der Agentur ist unveraendert: Ein Manager + mit der Kachel "creator" scheitert weiterhin. */ +{ + const a = await anmelden("creator", "CODE-MAN-0001", AGENTUR_WAND); ok(a.status === 401, `Manager-Code auf der Creator-Kachel bleibt abgewiesen (${a.status})`); } /* Wortgleichheit: "modi" von aussen anzugeben darf nicht anders klingen als eine erfundene Rolle. */ { - const m = await anmelden("modi", "FALSCH-FALSCH-1"); - const x = await anmelden("gibtesnicht", "FALSCH-FALSCH-1"); + /* AUF DER AGENTURWAND klingt „modi" wie eine erfundene Rolle -- + dort gibt es die Kachel nicht. Auf crew. gibt es sie, und dort + entscheidet der Code; deshalb wird das hier ausdruecklich an der + Agenturwand gefragt. */ + const m = await anmelden("modi", "FALSCH-FALSCH-1", AGENTUR_WAND); + const x = await anmelden("gibtesnicht", "FALSCH-FALSCH-1", AGENTUR_WAND); ok(m.status === 401 && x.status === 401 && JSON.stringify(m.daten) === JSON.stringify(x.daten), "Rolle \"modi\" von aussen klingt wie eine erfundene " @@ -152,7 +242,7 @@ for (const kachel of ["creator", "scout", "manager", "spicy", "admin"]) { } { - const a = await anmelden("creator", "CODE-MODI-FALSCH"); + const a = await anmelden("modi", "CODE-MODI-FALSCH"); ok(a.status === 401, `ein falscher Modi-Code wird abgewiesen (${a.status})`); } @@ -184,8 +274,16 @@ const LEUTE = [ ["Manager", "manager", "CODE-MAN-0001", false], ["Scout", "scout", "CODE-SCOU-0001", false], ["Creator", "creator", "CODE-ANNA-0001", false], - ["Modi Marina", "creator", "CODE-MODI-0001", true], - ["Rechte Hand", "creator", "CODE-HAND-0001", true], + /* AUF IHRER EIGENEN KACHEL (01.10.2026). Hier stand „creator" -- + der stille Zugang liess damals jede Kachel durch. Seit die Kachel + bindend ist, scheiterte ihre Anmeldung STILL: `unklar(...)` und + weiter, und acht Sichtbarkeitspruefungen fielen lautlos weg. + + Genau der Rueckgang, vor dem die Hausregel warnt -- gruen bei + weniger Pruefungen. Gefunden hat ihn nicht der Lauf, sondern der + Vergleich der Anzahl mit dem Lauf davor. */ + ["Modi Marina", "modi", "CODE-MODI-0001", true], + ["Rechte Hand", "hand", "CODE-HAND-0001", true], ]; async function hole(keks, pfad) { @@ -239,7 +337,7 @@ console.log("\n=== 3. Auch die ZAHL darf sie nicht mitzaehlen ===\n"); /* ---------- 4. Sehen die Modis einander? ----------------------------- */ console.log("\n=== 4. Die Modis sind untereinander ein Team ===\n"); { - const an = await anmelden("creator", "CODE-MODI-0001"); + const an = await anmelden("modi", "CODE-MODI-0001"); const { status, daten } = await hole(an.keks, "/workspace/api/personen"); if (status !== 200 || !Array.isArray(daten?.personen)) { unklar(`Personenwahl fuer den Modi nicht lesbar (${status})`); @@ -292,7 +390,8 @@ console.log("\n=== 5. Anlegen wie im Betrieb: DogFather legt einen Modi an ===\n vergessen worden, waeren oben trotzdem alle Haken gruen und kein einziger echter Modi kaeme herein. */ if (neuDaten?.code) { - const b = await anmelden("creator", neuDaten.code); + /* AUF DER MODI-KACHEL, seit dem 01.10.2026 -- vorher ging jede. */ + const b = await anmelden("modi", neuDaten.code); ok(b.status === 200 && b.daten?.rolle === "modi", "und meldet sich mit seinem Code an, ueber eine fremde Kachel " + `(${b.status}, ${b.daten?.rolle})`); @@ -314,7 +413,10 @@ console.log("\n=== 5. Anlegen wie im Betrieb: DogFather legt einen Modi an ===\n /* ---------- 6. Die Startseite eines Modis ---------------------------- */ console.log("\n=== 6. Was ein Modi auf seiner Startseite sieht ===\n"); { - const an = await anmelden("creator", "CODE-MODI-0001"); + /* AUF SEINER EIGENEN KACHEL, seit dem 01.10.2026. Hier stand + „creator" -- damals gab es fuer einen Modi keine eigene, und der + stille Zugang liess jede durch. Jetzt gilt die Kachel. */ + const an = await anmelden("modi", "CODE-MODI-0001"); const { status, daten } = await hole(an.keks, "/workspace/api/ich"); if (status !== 200) { unklar(`/api/ich nicht lesbar (${status})`); @@ -385,12 +487,40 @@ console.log("\n=== 7. Dieselbe Seite mit einem echten Browser ===\n"); seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); }); seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message)); - await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" }); - /* Irgendeine Kachel -- fuer einen Modi gibt es keine eigene. */ - await seite.click('.rolle[data-rolle="creator"]'); - await seite.fill("#code", "CODE-MODI-0001"); - await seite.click("button[type=submit]"); - await seite.waitForURL("**/start.html", { timeout: 15000 }); + /* ==== ANGEMELDET WIRD UEBER DIE WAND, NICHT UEBER DIE SEITE + (01.10.2026) + + Hier wurde bis heute im Browser auf die Creator-Kachel getippt + und der Modi-Code eingegeben -- das ging, solange der stille + Zugang jede Kachel durchliess. + + Seit die Kachel bindend ist, braeuchte der Browser die + CREW-Wand: Dort steht die Modi-Kachel. Ein Browser auf + 127.0.0.1 bekommt aber die Agenturwand, und ein Host-Kopf + laesst sich dort nur mit einer Namensumleitung setzen (so macht + es mess-reaktion mit `--host-resolver-rules`). + + Der kuerzere und ehrlichere Weg: an der richtigen Wand + anmelden und den Keks mitgeben. Gemessen werden soll, was ein + Modi auf seiner STARTSEITE sieht -- nicht, wie er hereinkommt. + Das steht in Abschnitt 1, und dort wird es an der echten Wand + gemessen. */ + const modiKeks = (await anmelden("modi", "CODE-MODI-0001")).keks; + await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => { + const [n, ...r] = z.split("="); + return { name: n, value: r.join("="), domain: "127.0.0.1", path: "/" }; + })); + await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" }); + /* KEIN `waitForURL` MEHR. Es wartete auf eine Navigation, die es + seit dem 01.10.2026 nicht mehr gibt -- angemeldet wird ueber + die Wand, nicht ueber das Formular. Steht die Seite schon da, + wartet es trotzdem und laeuft in die Frist. + + Und wenn der Keks NICHT angenommen wurde, sagt die Zeile + darunter genau das, statt fuenfzehn Sekunden zu schweigen. */ + if (!/start\.html/.test(seite.url())) { + unklar(`nach dem Anmelden steht die Seite auf ${seite.url()}`); + } await seite.waitForTimeout(1200); const bild = await seite.evaluate(() => ({ @@ -490,7 +620,7 @@ console.log("\n=== 8. Aufgaben, Einträge und Dateien eines Modis ===\n"); Der Kalender ist bewusst nicht dabei: termineSichtbar() gibt jedem nur Eigenes, dort kann nichts durchsickern. Nachgesehen, nicht angenommen. */ - const an = await anmelden("creator", "CODE-MODI-0001"); + const an = await anmelden("modi", "CODE-MODI-0001"); const MERKMAL = "GEHEIMER MODI-EINTRAG"; /* (a) Eine Aufgabe -- ueber den normalen Weg. */ diff --git a/server/pruef-team-ampel.mjs b/server/pruef-team-ampel.mjs index f29be1e7..097ee6d6 100644 --- a/server/pruef-team-ampel.mjs +++ b/server/pruef-team-ampel.mjs @@ -119,7 +119,7 @@ async function anmelden(rolle, code) { const holeLage = (keks) => fetch(`${BASIS}/workspace/api/teamlage`, { headers: { Cookie: keks } }); const keksDogi = await anmelden("admin", "CODE-DOGI-0001"); -const keksHand = await anmelden("creator", "CODE-HAND-0001"); +const keksHand = await anmelden("hand", "CODE-HAND-0001"); if (!keksDogi || !keksHand) { console.error("FEHLER: Anmeldung misslang -- ohne sie misst diese Datei nichts."); process.exit(1); diff --git a/server/pruef-team-stufen.mjs b/server/pruef-team-stufen.mjs index cbde5ada..1ba8266a 100644 --- a/server/pruef-team-stufen.mjs +++ b/server/pruef-team-stufen.mjs @@ -102,8 +102,8 @@ const setzeStufe = (keks, person_id, stufe) => }); const keksDogi = await anmelden("admin", "CODE-DOGI-0001"); -const keksHand = await anmelden("creator", "CODE-HAND-0001"); -const keksModi = await anmelden("creator", "CODE-MODI-0001"); +const keksHand = await anmelden("hand", "CODE-HAND-0001"); +const keksModi = await anmelden("modi", "CODE-MODI-0001"); if (!keksDogi || !keksHand || !keksModi) { console.error("FEHLER: Anmeldung misslang -- ohne sie misst diese Datei nichts."); process.exit(1); diff --git a/server/pruef-treff.mjs b/server/pruef-treff.mjs index 62fc4d30..87261127 100644 --- a/server/pruef-treff.mjs +++ b/server/pruef-treff.mjs @@ -211,7 +211,12 @@ for (const [name, host] of [["workspace.", HAUS], ["der Hauptseite", HAUPT]]) { } const kDogi = (await anmelden("admin", "CODE-DOGI-0001", HAUS)).keks; -const kModi = (await anmelden("creator", "CODE-MODI-0001", CREW)).keks; +/* AUF DER MODI-KACHEL (01.10.2026). Hier stand „creator" -- bis zum + 24.09. gab es fuer einen Modi keine eigene Kachel, und der stille + Zugang liess jede durch. Seit die Kachel bindend ist, scheiterte + die Anmeldung, und fuenf Pruefungen wurden rot, ohne dass am + Programm etwas falsch war. */ +const kModi = (await anmelden("modi", "CODE-MODI-0001", CREW)).keks; const kCrea = (await anmelden("creator", "CODE-CREA-0001", HAUS)).keks; const kMana = (await anmelden("manager", "CODE-MANA-0001", HAUS)).keks; ok([kDogi, kModi, kCrea, kMana].every((k) => k.length > 0), "die vier Vergleichsrollen sind angemeldet"); diff --git a/server/pruef-wunschliste.mjs b/server/pruef-wunschliste.mjs index 891301ac..81f91ac5 100644 --- a/server/pruef-wunschliste.mjs +++ b/server/pruef-wunschliste.mjs @@ -97,9 +97,9 @@ async function anmelden(kachel, code) { return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); } const dogi = await anmelden("admin", "CODE-DOGI-0001"); -const hand = await anmelden("creator", "CODE-HAND-0001"); -const modi = await anmelden("creator", "CODE-MODI-0001"); -const nane = await anmelden("creator", "CODE-NANE-0001"); +const hand = await anmelden("hand", "CODE-HAND-0001"); +const modi = await anmelden("modi", "CODE-MODI-0001"); +const nane = await anmelden("modi", "CODE-NANE-0001"); const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS }); diff --git a/server/workspace.js b/server/workspace.js index f43560ed..ded06aa7 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -6714,34 +6714,6 @@ workspaceRouter.use((req, res, next) => { return next(); }); -/** - * Gehoert dieser Code zu einem verborgenen Zugang? - * - * Gibt die Person zurueck oder null. `null` heisst hier ausdruecklich - * "nein oder nicht feststellbar" -- ohne Suchschluessel (etwa weil die - * Einstellung fehlt) gibt codeKennung() null zurueck, und dann wird - * niemand angemeldet. Das ist die richtige Richtung: Im Zweifel kommt - * niemand herein, statt dass im Zweifel jemand hereinkommt. - */ -function stillerZugang(code) { - try { - const kennung = codeKennung(code); - if (!kennung) return null; - const k = db().prepare( - "SELECT id, name, rolle, code_hash, code_salt, code_n FROM personen " - + `WHERE code_kennung = ? AND rolle IN (${ - [...TEAM_DOGI_ROLLEN].map((r) => `'${r}'`).join(", ")}) AND aktiv = 1`).get(kennung); - if (!k) return null; - /* Trotz Treffer wird geprueft. Der Suchschluessel ist ein - Wegweiser, kein Ausweis -- und ein Wegweiser, dem man blind - folgt, ist eine Hintertuer. */ - return gleich(hashe(code, k.code_salt, k.code_n), k.code_hash) ? k : null; - } catch (fehler) { - console.error("[workspace] Stiller Zugang nicht pruefbar:", fehler?.message); - return null; - } -} - /* DIE TAFEL LIEGT SEIT DEM 11.09.2026 IN workspace-rechte.js. Hier stand ein nur LESENDER Weg. Filipe: "so dass ich die da auch @@ -6763,95 +6735,49 @@ workspaceRouter.post("/workspace/api/anmelden", (req, res) => { const codeBrauchbar = code.length >= 4 && code.length <= 200; /* ================================================================= - DER STILLE ZUGANG (09.09.2026) + DIE KACHEL IST BINDEND (01.10.2026) - Wunsch Filipe: *"dass die keine neue eingangs kachel bekommen wie - spicy dogfather und so sondern einfach einen code. damit die von - der workspace auch nicht mal sehen dass die modis von mir einen - eigenen zugang haben."* + Filipe: „mach das. es soll fest sein." - Ein Modi oeffnet dieselbe Seite, tippt auf IRGENDEINE vorhandene - Kachel und gibt seinen Code ein. Welche Kachel, ist gleichgueltig - -- der Code allein entscheidet. Von aussen sieht das aus wie jede - andere Anmeldung: dieselbe Seite, dieselbe Anfrage, dieselben - Felder. + VanVan hatte gemeldet: „Man kann sich mit seinem Zugangscode + immer noch über jeden Button der Startseite anmelden, egal + welche Rolle man hat." - ZWEI NAHELIEGENDE WEGE, DIE ABSICHTLICH NICHT GEWAEHLT WURDEN: + --------------------------------------------------------------- + HIER STAND DER STILLE ZUGANG (09.09. bis 01.10.2026) - * Ein Merkmal im Code ("M-..."): waere ein sichtbares Kennzeichen - auf dem Zettel des Modis. Wer den Code sieht, sieht die Sorte. - * Eine eigene Adresse (/modi.html): waere eine Seite, die man - finden kann -- und die Seitenpruefung zaehlt Seiten. + Er liess einen Team-Dogi-Code auf JEDER Kachel durch. Das war + kein Versehen, sondern Filipes Entscheidung vom 09.09.2026: + „dass die keine neue eingangs kachel bekommen wie spicy + dogfather und so sondern einfach einen code. damit die von der + workspace auch nicht mal sehen dass die modis von mir einen + eigenen zugang haben." - WARUM DAS VOR DEM GEWOHNTEN WEG STEHT UND NICHT DAHINTER: Ein - Rueckfall NACH einem Fehlversuch haette den gewohnten Weg - verlaengert -- und zwar nur dann, wenn er scheitert. Genau daran - waere es zu erkennen gewesen: Fehlversuche dauern ploetzlich - laenger als frueher. Der Suchschluessel kostet Mikrosekunden und - trifft in aller Regel nichts; fuer alle anderen bleibt der Ablauf - unveraendert, auch in der Zeit. + Wer keine Kachel hat, muss irgendeine nehmen koennen. - DER SUCHSCHLUESSEL ALLEIN LAESST NIEMANDEN HEREIN. Er sagt nur, - WEN man pruefen soll -- danach entscheidet scrypt wie ueberall. */ - /* AUF DEN ALTEN ADRESSEN WIRD DER VERBORGENE ZUGANG GAR NICHT ERST - GEFRAGT (Entscheidung Filipe, 10.09.2026). + WARUM ER JETZT WEG KANN -- und das ist der ganze Punkt: Seit + der Haustrennung am 24.09.2026 gibt es ZWEI Waende. Auf `crew.` + steht ein eigener Kachelsatz (CREW_KACHEL): DogFather, rechte + Hand, linke Hand, Modi, Community. Alle fuenf Rollen haben dort + ihre Kachel. - Vorher stand hier eine Weiterleitung: Wer seinen Code noch auf - workspace.dogfather-universe.com eintippte, bekam keine Sitzung, - aber den Weg zur neuen Adresse. Filipes Entscheidung dagegen: - "gar nichts -- Code stimmt nicht". Die alte Wand soll sich - verhalten, als waere der Code erfunden. + Das Verbergen leistet seither die ADRESSE. Wer sie nicht kennt, + findet die Wand nicht; wer sie kennt, sieht die Rollennamen + ohnehin offen darauf stehen. Der Trick mit der beliebigen + Kachel hat niemanden mehr geschuetzt und nur noch dafuer + gesorgt, dass die Wahl folgenlos blieb. - WARUM DAS NICHT NUR EINE ANDERE ANTWORT IST, SONDERN EIN ANDERER - WEG: Haette ich hier bloss `return 401` gesetzt, waere der Ablauf - trotzdem ein anderer geblieben -- ein Suchschluessel-Treffer und - EIN scrypt-Durchlauf statt der Kandidatenschleife der gewaehlten - Kachel. Das ist messbar, und Zeitunterschiede sind genau die - Spur, die dieser ganze Zugang vermeiden soll. + WAS SICH NICHT AENDERT: Auf der Agenturwand war der stille + Zugang nie aktiv. Ein Team-Dogi-Code verhaelt sich dort + weiterhin wie ein erfundener -- gleiche Antwort, gleicher Weg, + gleiche Dauer. Dafuer sorgt der Kachelsatz unten, nicht eine + eigene Bedingung. - Deshalb wird `stillerZugang` auf diesen drei Adressen ueberhaupt - nicht aufgerufen. Der Code faellt danach durch den gewohnten Weg - wie jeder unbekannte: dieselbe Schleife, derselbe Eintrag in - `versuche`, dieselbe Antwort, dieselbe Dauer. Die alte Wand - verhaelt sich damit exakt so wie vor dem Tag, an dem es diese - Rollen gab. - - DER PREIS, und er gehoert genannt: Ein Modi, der die alte - Verknuepfung auf dem Handy hat, sammelt dort Fehlversuche wie - jeder andere auch. Acht in zehn Minuten sperren seine IP -- und - zwar auch fuer die neue Adresse, denn die Sperre haengt an der - IP, nicht am Hostnamen. Das ist der Preis der Stille; er faellt - nur an, wenn jemand die alte Adresse mehrfach probiert. */ - /* UND AUCH NICHT AUF DER WAND DES TREFFS (11.09.2026). - - Hier stand `!istOhneModiAdresse(...)` -- also "ueberall ausser auf - den alten Adressen". Als dritte Wand dazukam, hiess das - stillschweigend auch: dort. Ein Modi kam damit ueber den - verborgenen Weg in den Treff herein, obwohl die Kachelliste dort - nur `gast` kennt und die Adressregel ihn abweist. - - Gefunden hat das nicht das Lesen, sondern eine Zeile in - pruef-treff, die das GEGENTEIL behauptete und rot wurde: - "auf treff. kommt sonst niemand herein -- auch DogFather nicht - (401/200)". DogFather wurde abgewiesen, der Modi nicht. - - Die Lehre ist dieselbe wie bei `null` in der Rechtetafel: Eine - Bedingung, die durch AUSSCHLIESSEN formuliert ist, nimmt jede - neue Moeglichkeit automatisch mit auf. Jetzt steht dort, WO der - Weg gilt, statt wo er nicht gilt. */ - const stilleWand = istCrewAdresse(req.get("host")) || istPruefAdresse(req.get("host")); - const still = codeBrauchbar && stilleWand ? stillerZugang(code) : null; - if (still) { - db().prepare("DELETE FROM versuche WHERE ip = ?").run(ip); - db().prepare("UPDATE personen SET letzter_login = ? WHERE id = ?").run(jetzt(), still.id); - sitzungSetzen(res, still, req); - protokolliere("anmeldung", { - personId: still.id, rolle: still.rolle, ip, detail: still.name, - }); - return res.json({ - weiter: "/workspace/start.html", name: still.name, rolle: still.rolle, - }); - } + `code_kennung` in `personen` wird weiter GESCHRIEBEN, aber + nicht mehr gelesen. Sie war der Suchschluessel dieses Weges. + Stehen gelassen und nicht geloescht: Eine Spalte zu entfernen + ist eine Schemaaenderung mit Sicherung, und sie kostet nichts. + Wer sie wieder braucht, findet hier, wofuer sie da war. */ /* Ab hier der gewohnte Weg -- unveraendert. 'modi' ist keine Kachel-Rolle und faellt deshalb in dieselbe Antwort wie eine @@ -6885,7 +6811,24 @@ workspaceRouter.post("/workspace/api/anmelden", (req, res) => { Wand gerade dran ist. Ein Manager, der crew. erraet und seinen Code eintippt, faellt dadurch in genau dieselbe Antwort wie jemand mit einer erfundenen Rolle. */ - const kachelSatz = istCrewAdresse(req.get("host")) ? CREW_KACHEL : ROLLEN_KACHEL; + /* ==== EINE PRUEFADRESSE IST KEINE WAND (01.10.2026) ========== + + `127.0.0.1` ist weder crew. noch die Agentur. Bis heute fiel + das nicht auf: Der stille Zugang liess Team-Dogi-Codes dort + ohnehin durch, egal welcher Kachelsatz galt. Mit seinem + Wegfall gaelte dort der AGENTUR-Satz -- und damit kaeme kein + einziger Modi mehr herein. Fuenfzig Pruefdateien melden + Team-Rollen ueber diese Adresse an; sie waeren alle rot, und + zwar wegen der Messumgebung, nicht wegen des Programms. + + Auf einer Adresse ohne Wand gibt es deshalb ALLE Kacheln. Das + versteckt nichts: Welche Kachel auf welcher ECHTEN Wand steht, + entscheiden weiterhin die zwei Mengen darunter, und genau das + misst pruef-modi-verborgen -- mit ausdruecklichem Host-Kopf, + nicht ueber 127.0.0.1. */ + const kachelSatz = istPruefAdresse(req.get("host")) + ? new Set([...ROLLEN_KACHEL, ...CREW_KACHEL]) + : (istCrewAdresse(req.get("host")) ? CREW_KACHEL : ROLLEN_KACHEL); if (!kachelSatz.has(rolle) || !codeBrauchbar) { db().prepare("INSERT INTO versuche (ip, zeitpunkt) VALUES (?,?)").run(ip, jetzt()); diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 0685f0ee..f26386f1 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,8 +16,8 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +