import { generateKeyPairSync } from "node:crypto"; import { describe, expect, it } from "vitest"; import { authorizedKeysAbgleichen } from "@/lib/ssh/abgleich"; import { blockSetzen, type SollEintrag } from "@/lib/ssh/authorized-keys"; import { fingerprintSha256 } from "@/lib/ssh/openssh"; /** Abgleich einer authorized_keys mit dem Soll (#021). */ function key(kommentar: string) { const { publicKey } = generateKeyPairSync("ed25519"); const roh = publicKey.export({ format: "der", type: "spki" }).subarray(-32); const typ = Buffer.from("ssh-ed25519"); const blob = Buffer.concat([Buffer.from([0, 0, 0, typ.length]), typ, Buffer.from([0, 0, 0, 32]), roh]); return { publicKey: `ssh-ed25519 ${blob.toString("base64")} ${kommentar}`, fingerprint: fingerprintSha256(blob), }; } const DEPLOY = key("deploy"); const BACKUP = key("backup"); const FREMD = key("hacker@irgendwo"); const BEKANNT = key("bekannt"); const soll: SollEintrag[] = [DEPLOY, { ...BACKUP, optionen: 'from="10.0.0.1"' }]; const bekannt = new Set([DEPLOY.fingerprint, BACKUP.fingerprint, BEKANNT.fingerprint]); describe("authorized_keys abgleichen", () => { it("ist ohne Befund, wenn der Block dem Soll entspricht", () => { const inhalt = blockSetzen(`${BEKANNT.publicKey}\n`, soll).inhalt; const ergebnis = authorizedKeysAbgleichen(inhalt, soll, bekannt, { sshVerzeichnis: "700", datei: "600", eigentuemerPasst: true, }); expect(ergebnis.befunde).toEqual([]); expect(ergebnis.vorhanden).toEqual([DEPLOY.fingerprint, BACKUP.fingerprint]); expect(ergebnis.eintraege.map((e) => e.herkunft)).toEqual(["bekannt", "verwaltet", "verwaltet"]); }); it("findet fehlende, geaenderte und zusaetzliche Keys im Block", () => { const inhalt = blockSetzen("", [DEPLOY, BACKUP, FREMD]).inhalt; // BACKUP ohne Optionen, FREMD zu viel const arten = authorizedKeysAbgleichen(inhalt, soll, bekannt).befunde.map((b) => [b.art, b.fingerprint]); expect(arten).toEqual([ ["ZUSAETZLICH_IM_BLOCK", BACKUP.fingerprint], ["ZUSAETZLICH_IM_BLOCK", FREMD.fingerprint], ]); const leer = authorizedKeysAbgleichen(null, soll, bekannt).befunde.map((b) => b.art); expect(leer).toEqual(["FEHLENDER_SCHLUESSEL", "FEHLENDER_SCHLUESSEL"]); }); it("meldet nur unbekannte Keys ausserhalb des Blocks", () => { const inhalt = blockSetzen(`${FREMD.publicKey}\n${FREMD.publicKey}\n${BEKANNT.publicKey}\n`, soll).inhalt; const befunde = authorizedKeysAbgleichen(inhalt, soll, bekannt).befunde; expect(befunde).toHaveLength(1); expect(befunde[0]).toMatchObject({ art: "UNBEKANNTER_SCHLUESSEL", fingerprint: FREMD.fingerprint }); expect(befunde[0]?.text).toContain("hacker@irgendwo"); }); it("prueft Rechte und Eigentuemer", () => { const befunde = authorizedKeysAbgleichen("", [], bekannt, { sshVerzeichnis: "777", datei: "664", eigentuemerPasst: false, }).befunde; expect(befunde.map((b) => b.art)).toEqual(["RECHTE", "RECHTE", "RECHTE"]); expect( authorizedKeysAbgleichen("", [], bekannt, { sshVerzeichnis: "755", datei: "644", eigentuemerPasst: true, }).befunde, ).toEqual([]); }); it("meldet einen beschaedigten Block", () => { expect(authorizedKeysAbgleichen("# BEGIN SSHKV MANAGED\n", [], bekannt).befunde[0]?.art).toBe( "DATEI_GEAENDERT", ); }); });