Files
dogfather-universe/server/workspace-code.js
T
DogFatherGit 6d9bad880c Workspace: echte Besucher-IP statt Cloudflare-Adresse
Gefunden beim Nachsehen im Protokoll nach der ersten echten Anmeldung:
Jeder Eintrag trug dieselbe IP 172.69.220.140 -- eine Cloudflare-Adresse.

Ursache: Die Kette ist Besucher -> Cloudflare -> Caddy -> Express, aber
`trust proxy` steht auf 1. Express nimmt daher den letzten Eintrag aus
X-Forwarded-For, und das ist Cloudflare.

Auswirkung war nicht nur ein unbrauchbares Protokoll, sondern vor allem:
ALLE Nutzer teilten sich einen einzigen Sperr-Zaehler. Beim ersten
Anmelden waren nach zwei Tippfehlern plus drei Testversuchen bereits
5 von 8 verbraucht -- drei weitere und der Zugang waere fuer alle
gesperrt gewesen.

Jetzt wird CF-Connecting-IP ausgewertet (setzt Cloudflare bei jeder
Anfrage selbst, vom Besucher nicht faelschbar), mit Rueckfall auf die
Peer-Adresse. `trust proxy` bleibt bewusst unangetastet, damit die
Aenderung nur /workspace betrifft und nicht die ganze Website.

Geprueft: 8 Fehlversuche von IP A sperren IP A (429), IP B bekommt
weiterhin 401 und kann sich normal anmelden (200).

Ausserdem: Spaltenbreite im Protokoll-Ausdruck korrigiert -- bei
`anmeldung_fehlgeschlagen` (genau 24 Zeichen) klebte die Rolle am Namen.
2026-08-27 22:53:51 +02:00

105 lines
3.8 KiB
JavaScript

#!/usr/bin/env node
/* =====================================================================
workspace-code.js — Zugangscodes für den Creator Workspace verwalten.
Läuft NUR auf der Kommandozeile des Servers. Der Code wird dabei einmal
angezeigt und danach nirgends mehr gespeichert -- in der Datenbank liegt
ausschließlich sein scrypt-Hash. Geht ein Code verloren, wird ein neuer
erzeugt; wiederherstellen lässt er sich nicht. Das ist Absicht.
Aufrufe:
node server/workspace-code.js liste
node server/workspace-code.js anlegen "Dogfather" admin
node server/workspace-code.js neu 3
node server/workspace-code.js sperren 3
node server/workspace-code.js entsperren 3
node server/workspace-code.js protokoll [anzahl]
===================================================================== */
import {
personAnlegen, personenListe, personSperren, codeNeu, protokollLesen,
} from "./workspace.js";
const [, , befehl, ...rest] = process.argv;
function zeigeCode(p) {
const linie = "─".repeat(52);
console.log(`\n${linie}`);
console.log(` ${p.name} · Rolle: ${p.rolle} · Nummer: ${p.id}`);
console.log(` Zugangscode: ${p.code}`);
console.log(`${linie}`);
console.log(" Dieser Code wird NUR JETZT angezeigt. Sicher weitergeben");
console.log(" (z. B. über Bitwarden) und hier nicht notieren.\n");
}
try {
switch (befehl) {
case "anlegen": {
const [name, rolle] = rest;
if (!name || !rolle) throw new Error('Aufruf: anlegen "Name" <admin|creator|scout>');
zeigeCode(personAnlegen(name, rolle));
break;
}
case "neu": {
const id = Number(rest[0]);
if (!id) throw new Error("Aufruf: neu <Nummer>");
zeigeCode(codeNeu(id));
console.log(" Alle offenen Sitzungen dieser Person wurden beendet.\n");
break;
}
case "sperren":
case "entsperren": {
const id = Number(rest[0]);
if (!id) throw new Error(`Aufruf: ${befehl} <Nummer>`);
personSperren(id, befehl === "entsperren");
console.log(`Person ${id} ist jetzt ${befehl === "entsperren" ? "aktiv" : "gesperrt"}.`);
break;
}
case "liste": {
const alle = personenListe();
if (!alle.length) { console.log("Noch keine Personen angelegt."); break; }
console.log("\n Nr Rolle Name Status Sitzungen Letzte Anmeldung");
console.log(" ".padEnd(78, "─"));
for (const p of alle) {
console.log(
` ${String(p.id).padStart(2)} ${p.rolle.padEnd(8)} ${p.name.slice(0, 20).padEnd(20)} `
+ `${(p.aktiv ? "aktiv" : "gesperrt").padEnd(9)} ${String(p.sitzungen).padStart(6)} `
+ `${p.letzter_login ? p.letzter_login.slice(0, 16).replace("T", " ") : "—"}`);
}
console.log("");
break;
}
case "protokoll": {
const eintraege = protokollLesen(Number(rest[0]) || 20);
if (!eintraege.length) { console.log("Protokoll ist leer."); break; }
console.log("");
for (const e of eintraege) {
console.log(` ${e.zeitpunkt.slice(0, 19).replace("T", " ")} ${(e.aktion || "").padEnd(26)}`
+ `${(e.rolle || "—").padEnd(8)} ${(e.detail || "").padEnd(18)} ${e.ip || ""}`);
}
console.log("");
break;
}
default:
console.log(`
Zugangscodes für den Creator Workspace
liste alle Personen anzeigen
anlegen "Name" <rolle> Person anlegen, Code wird einmal angezeigt
neu <Nr> neuen Code erzeugen (beendet alte Sitzungen)
sperren <Nr> / entsperren <Nr> Zugang sperren oder wieder freigeben
protokoll [Anzahl] letzte Einträge des Audit-Logs
Rollen: admin, creator, scout
`);
}
} catch (fehler) {
console.error(`\nFehler: ${fehler.message}\n`);
process.exit(1);
}