CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
Mail-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
Frontend (web/mail-search): Anhang-Vorschau fuer PDF (Canvas-Rendering via pdfjs-dist, gleiches Muster wie DOC-05s web/pdf-viewer/PdfViewer.tsx -- kein aequivalentes PdfCanvasPreview im Repo gefunden, daher PdfViewer als Vorlage uebernommen statt neu erfunden) und Bilder (<img> auf einem authentifiziert geladenen Blob). Die Vorschauart haengt ausschliesslich vom serverseitig per Magic-Bytes bestimmten contentType ab, nie von einem Dateinamen (den es an der Schnittstelle gar nicht gibt); nicht unterstuetzte Typen werden nur als Hinweistext angezeigt, nie eingebettet. Kein iframe/<object>/dangerouslySetInnerHTML -- durch automatisierten Sicherheitsreview-Test abgesichert. Neue lib/http.ts (authentifizierter Zugriff ueber @nexarch/shl, identisch zu web/pdf-viewer/lib/http.ts) und lib/attachments.ts (Anhangsliste/ -inhalt der Mail-API). Pruefprotokoll in mail/docs/UX-03-PRUEFPROTOKOLL.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
34 lines
1.5 KiB
TypeScript
34 lines
1.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const dir = dirname(fileURLToPath(import.meta.url));
|
|
|
|
// UX-03 Pflichtprüfung 2: Sicherheitsreview bestätigt automatisiert (statt
|
|
// nur behauptet): keine iframe-Einbindung von Anhangsinhalt, kein <object>,
|
|
// kein dangerouslySetInnerHTML -- über alle an der Anhang-Vorschau
|
|
// beteiligten Dateien. archivmail hatte testweise eine iframe-PDF-Vorschau,
|
|
// als unsicher verworfen; dieser Test verhindert ein Wiederauftreten.
|
|
const previewFiles = ["PdfCanvasPreview.tsx", "ImagePreview.tsx", "AttachmentPreview.tsx", "AttachmentList.tsx"];
|
|
|
|
const forbiddenPatterns = [/<iframe/i, /<object/i, /dangerouslysetinnerhtml/i];
|
|
|
|
// Kommentare erklären absichtlich, WARUM kein iframe/object verwendet wird
|
|
// (enthalten die Begriffe also selbst als Prosa) -- der Review prüft den
|
|
// tatsächlichen Code, daher werden Kommentare vor dem Abgleich entfernt.
|
|
function stripComments(source: string): string {
|
|
return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
}
|
|
|
|
describe("Sicherheitsreview: Anhang-Vorschau rendert nie Fremdinhalt unkontrolliert", () => {
|
|
for (const file of previewFiles) {
|
|
it(`${file} enthält kein iframe/object/dangerouslySetInnerHTML im tatsächlichen Code`, () => {
|
|
const code = stripComments(readFileSync(join(dir, file), "utf-8"));
|
|
for (const pattern of forbiddenPatterns) {
|
|
expect(code).not.toMatch(pattern);
|
|
}
|
|
});
|
|
}
|
|
});
|