feat(zuweisungen): Matrix Schluessel x Host mit CSV-Export (#025)
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>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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";
|
||||
}
|
||||
Reference in New Issue
Block a user