Anmeldung, Einrichtung des zweiten Faktors fuer den Notfall-Admin, erneute Bestaetigung vor kritischen Aktionen und die Seite fuer fehlende Rechte. Die Huelle zeigt jetzt den echten Benutzer, und jede Seite prueft die Sitzung selbst; ein struktureller Test haelt das fest. Die Ablaeufe sind im gebauten Stand gegen den Mock-OIDC geprueft (pnpm test:e2e): Admin, Konto ohne Gruppe, Notfall-Admin mit TOTP. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
1.9 KiB
TypeScript
46 lines
1.9 KiB
TypeScript
import { readFileSync, readdirSync, statSync } from "node:fs";
|
||
import path from "node:path";
|
||
import { describe, expect, it } from "vitest";
|
||
|
||
/**
|
||
* Struktureller Test (#004, Muster aus Laufzettel): jede Seite und jeder Route Handler
|
||
* prueft selbst, wer zugreift. Die Ausnahmen stehen hier namentlich mit Begruendung – ein
|
||
* neuer ungepruefter Handler soll jemanden zwingen, sie aufzuschreiben.
|
||
*/
|
||
const AUSNAHMEN: Record<string, string> = {
|
||
"src/app/anmelden/page.tsx": "Anmeldeseite selbst",
|
||
"src/app/anmelden/totp/page.tsx": "nur mit Einrichtungs-Cookie aus richtigem Passwort erreichbar",
|
||
"src/app/api/auth/abmelden/route.ts": "Abmelden braucht keine Pruefung",
|
||
"src/app/api/auth/oidc/start/route.ts": "Beginn der Anmeldung",
|
||
"src/app/api/auth/oidc/rueckruf/route.ts": "Ende der Anmeldung; prueft state, nonce und PKCE",
|
||
"src/app/api/gesundheit/route.ts": "Healthcheck, verraet nur die Version",
|
||
};
|
||
|
||
const PRUEFUNGEN = /sitzungErforderlich\(|rechtErforderlich\(|totpEinrichtungLesen\(/;
|
||
|
||
function dateien(verzeichnis: string): string[] {
|
||
return readdirSync(verzeichnis).flatMap((name) => {
|
||
const pfad = path.join(verzeichnis, name);
|
||
if (statSync(pfad).isDirectory()) return dateien(pfad);
|
||
return /^(page\.tsx|route\.ts)$/.test(name) ? [pfad] : [];
|
||
});
|
||
}
|
||
|
||
describe("Zugangspruefung", () => {
|
||
const alle = dateien("src/app").map((p) => p.split(path.sep).join("/"));
|
||
|
||
it("findet Seiten und Handler", () => {
|
||
expect(alle.length).toBeGreaterThan(10);
|
||
});
|
||
|
||
it.each(alle)("%s prueft selbst oder steht in den Ausnahmen", (datei) => {
|
||
if (AUSNAHMEN[datei]) return;
|
||
const inhalt = readFileSync(datei, "utf8");
|
||
expect(PRUEFUNGEN.test(inhalt), `${datei} prueft keine Sitzung`).toBe(true);
|
||
});
|
||
|
||
it("listet keine Ausnahme fuer eine Datei, die es nicht mehr gibt", () => {
|
||
for (const datei of Object.keys(AUSNAHMEN)) expect(alle).toContain(datei);
|
||
});
|
||
});
|