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.
105 lines
3.8 KiB
JavaScript
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);
|
|
}
|