import { test, describe, before, after } from "node:test"; import assert from "node:assert/strict"; import { encryptCredential, decryptCredential, isEncryptedCredential, _resetKeyCacheForTests, } from "../../src/lib/credential-crypto.ts"; /** * Ver-/Entschlüsselung ruhender Kalender-Zugangsdaten. * * Beobachtbares Verhalten: ein verschlüsselter Wert lässt sich mit demselben Schlüssel wieder * lesbar machen; ein Alt-Klartextwert (vor dieser Änderung in der DB) bleibt unverändert lesbar; * ein manipulierter Geheimtext fällt auf, statt stillschweigend falsche Daten zu liefern. * * CREDENTIAL_ENCRYPTION_KEY wird vor jedem Test gesetzt (deterministischer Test-Schlüssel, * keine echte Produktionsvariable) -- loadKey() liest die Env-Var erst beim ersten Ver-/ * Entschlüsseln, nicht beim Modul-Import, deshalb reicht das hier statt eines Mocks. */ const TEST_KEY = Buffer.alloc(32, 7).toString("base64"); describe("credential-crypto", () => { before(() => { process.env.CREDENTIAL_ENCRYPTION_KEY = TEST_KEY; _resetKeyCacheForTests(); }); after(() => _resetKeyCacheForTests()); test("Roundtrip: verschlüsselt und wieder entschlüsselt ergibt das Original", () => { const plain = "someone@icloud.com:app-specific-password-123"; const cipher = encryptCredential(plain); assert.notEqual(cipher, plain); assert.equal(decryptCredential(cipher), plain); }); test("Verschlüsselter Wert trägt das enc1-Präfix, Klartext nicht", () => { const cipher = encryptCredential("secret"); assert.equal(isEncryptedCredential(cipher), true); assert.equal(isEncryptedCredential("plain-old-value"), false); }); test("Alt-Klartext ohne enc1-Präfix bleibt beim Entschlüsseln unverändert", () => { // Simuliert eine bestehende DB-Zeile von vor dieser Änderung. const legacy = "user@example.com:hunter2"; assert.equal(decryptCredential(legacy), legacy); }); test("zwei Verschlüsselungen desselben Werts ergeben unterschiedliche Geheimtexte", () => { // Zufälliger IV pro Aufruf -- wichtig, damit gleiche Passwörter nicht denselben // Geheimtext ergeben (das würde sie in der DB als "gleich" erkennbar machen). const a = encryptCredential("same-password"); const b = encryptCredential("same-password"); assert.notEqual(a, b); assert.equal(decryptCredential(a), "same-password"); assert.equal(decryptCredential(b), "same-password"); }); test("manipulierter Geheimtext wird beim Entschlüsseln abgelehnt", () => { const cipher = encryptCredential("secret-value"); const tampered = cipher.slice(0, -4) + "abcd"; assert.throws(() => decryptCredential(tampered)); }); test("falsches enc1-Format wirft statt still falsche Daten zu liefern", () => { assert.throws(() => decryptCredential("enc1:nur-ein-teil")); }); });