feat(platzhalter): Aufloesung, Namensregeln und Shell-Maskierung
Aus einer Vorlage wird hier der PowerShell-Befehl, den ein Techniker kopiert und
auf einem Domaenencontroller ausfuehrt. Entsprechend dicht ist die Abdeckung:
810 Tests, und die Maskierung wird **ausgefuehrt** geprueft, nicht gelesen.
- Platzhalter aus Geraet, Lauf, Mitarbeiter und Abteilung, dazu die Variablen
der Vorlage; ein unbekannter bleibt sichtbar stehen
- `{{ou}}` ist der Eltern-Container des DN — genau der Pfad fuer New-ADUser
- Namensregeln fuer upn, sam, mail und hostname mit Transliteration, `{v}`,
`{nnn}` und `{kundenkuerzel}`; Kundenregeln ueberlagern die globalen feldweise
- Maskierung je Shell, Skript-Kopie je Abschnitt mit Kommentarzeilen
- `{{generiertes_passwort}}`: 20 Zeichen, bei jeder Anzeige neu, nirgends
gespeichert; im Druck `[Passwort – nicht gespeichert]`
Der unabhaengige Review fand drei Blocker. Der schwerste war eine
Codeausfuehrung: PowerShell liest auch `“`, `”` und `„` als Begrenzer einer
Zeichenkette, die Maskierung kannte nur das ASCII-Zeichen. Ein Abteilungsname
aus Word — Word wandelt `"` von selbst um — reichte. Gefunden hat es der Review
nicht durch Lesen, sondern indem er sich PowerShell in einen Container geholt
und die Markierungsdatei hat entstehen lassen. Der Test dagegen hatte sich still
uebersprungen; er nimmt jetzt selbst das Abbild und bricht in CI ab.
Dazu: zwei verschiedene Passwoerter in einer Antwort (Anzeige und Skript wurden
getrennt gefuellt), eine Vorlagenvariable, die `{{techniker}}` und `{{kunde}}`
ueberschreiben konnte, und die tragende Annahme der Maskierung — dass der
Platzhalter in Anfuehrungszeichen steht —, die niemand geprueft hat.
Schliesst #012
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f85bc87324
commit
b59fbb4645
@@ -0,0 +1,51 @@
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { Markdown } from "@/components/markdown";
|
||||
import { platzhalterErsetzen } from "@/lib/platzhalter-werte";
|
||||
|
||||
/**
|
||||
* Was von einem ersetzten Wert wirklich im HTML ankommt (#012).
|
||||
*
|
||||
* Das Akzeptanzkriterium lautet: „ein Wert mit `<script>` landet HTML-escaped in
|
||||
* der Anzeige“. Erfuellt wird es von React und nicht von eigenem Code — und
|
||||
* genau deshalb steht hier ein Test, der das **am gerenderten HTML** nachweist.
|
||||
* Eine eigene Maskierung waere doppelt und machte aus „Forschung & Entwicklung“
|
||||
* sichtbar „Forschung &amp; Entwicklung“.
|
||||
*/
|
||||
|
||||
describe("Ersetzter Wert im gerenderten HTML", () => {
|
||||
it("maskiert ein script-Element im Schritt-Titel", () => {
|
||||
const { text } = platzhalterErsetzen("Konto für {{mitarbeiter}} anlegen", {
|
||||
mitarbeiter: "<script>alert(1)</script>",
|
||||
});
|
||||
const html = renderToStaticMarkup(<h3>{text}</h3>);
|
||||
expect(html).not.toContain("<script>");
|
||||
expect(html).toContain("<script>");
|
||||
});
|
||||
|
||||
it("zeigt ein Ampersand als Zeichen, nicht als Entität", () => {
|
||||
// Der alltaegliche Fall – „Forschung & Entwicklung“ ist ein Abteilungsname
|
||||
// und kein Angriff. Doppelt maskiert stuende hier „&amp;“.
|
||||
const { text } = platzhalterErsetzen("{{abteilung}}", {
|
||||
abteilung: "Forschung & Entwicklung",
|
||||
});
|
||||
const html = renderToStaticMarkup(<p>{text}</p>);
|
||||
expect(html).toBe("<p>Forschung & Entwicklung</p>");
|
||||
});
|
||||
|
||||
it("lässt ein script-Element auch im Hilfetext nicht durch", () => {
|
||||
// Der Hilfetext geht durch Markdown, das ebenfalls maskiert und rohes HTML
|
||||
// fallen laesst (#010).
|
||||
const { text } = platzhalterErsetzen("Hinweis für {{mitarbeiter}}", {
|
||||
mitarbeiter: "<img src=x onerror=alert(1)>",
|
||||
});
|
||||
const html = renderToStaticMarkup(<Markdown text={text} />);
|
||||
expect(html).not.toContain("<img");
|
||||
expect(html).toContain("<img");
|
||||
});
|
||||
|
||||
it("zeigt einen unbekannten Platzhalter sichtbar an", () => {
|
||||
const { text } = platzhalterErsetzen("{{tipfehler}} prüfen", {});
|
||||
expect(renderToStaticMarkup(<span>{text}</span>)).toBe("<span>{{tipfehler}} prüfen</span>");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user