Bisher liess sich nur je Schluessel oder je Host nachsehen, wo ein Key verwaltet ist. Die Matrix zeigt das auf einen Blick, loest Hostgruppen-Zuweisungen je Mitglied auf (P vs. P·G) und macht nicht synchrone Zustaende ohne Farbe erkennbar. Die Matrix plant nur: Zuweisen und Entfernen laufen ueber die vorhandenen Aktionen, ausgerollt wird weiter per Dry-Run auf der Schluesselseite. Der Aufbau ist eine reine Funktion in src/lib, damit Seite und CSV-Export garantiert dasselbe zeigen und die Gruppenaufloesung ohne Datenbank testbar ist. Der CSV-Export entschaerft Formelbeginne, weil Schluesselnamen frei waehlbar sind und Excel sie sonst ausfuehren wuerde. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
/**
|
||
* CSV fuer Excel (#025). Framework-frei, damit spaetere Exporte (Protokoll, Phase 5) dieselben
|
||
* Regeln nutzen.
|
||
*
|
||
* - Semikolon als Trenner und UTF-8-BOM: ein deutsches Excel oeffnet die Datei sonst als eine
|
||
* Spalte mit kaputten Umlauten.
|
||
* - Jeder Wert in Anfuehrungszeichen, damit Kommas in `authorized_keys`-Optionen und
|
||
* Zeilenumbrueche nichts verschieben.
|
||
* - Formel-Injektion: Excel und LibreOffice werten Zellen, die mit `= + - @` (oder Tab/CR)
|
||
* beginnen, als Formel aus – ein Schluesselname wie `=HYPERLINK(…)` wuerde beim Oeffnen
|
||
* ausgefuehrt. Ein vorangestelltes `'` macht daraus Text (OWASP „CSV Injection“).
|
||
*/
|
||
export const CSV_BOM = "";
|
||
export const CSV_TRENNER = ";";
|
||
|
||
const FORMELBEGINN = /^[=+\-@\t\r]/;
|
||
|
||
export function csvEntschaerfen(wert: string): string {
|
||
return FORMELBEGINN.test(wert) ? `'${wert}` : wert;
|
||
}
|
||
|
||
export function csvWert(wert: string | number | null | undefined): string {
|
||
const text = csvEntschaerfen(wert == null ? "" : String(wert));
|
||
return `"${text.replace(/"/g, '""')}"`;
|
||
}
|
||
|
||
export function csvZeile(werte: readonly (string | number | null | undefined)[]): string {
|
||
return werte.map(csvWert).join(CSV_TRENNER);
|
||
}
|
||
|
||
/** Ganze Datei: BOM, Kopfzeile, Datenzeilen, CRLF wie Excel selbst. */
|
||
export function csvDatei(
|
||
kopf: readonly string[],
|
||
zeilen: readonly (readonly (string | number | null | undefined)[])[],
|
||
): string {
|
||
return CSV_BOM + [kopf, ...zeilen].map(csvZeile).join("\r\n") + "\r\n";
|
||
}
|