UNPKG

fortencrypt

Version:

Node.js encryption library made effortless — configure once, encrypt everywhere. TypeScript-ready, CLI-ready, secure AES-256-GCM and digital signature support.

195 lines 8.5 kB
// test/crypto.test.ts import crypto from "crypto"; import fs from "fs/promises"; import path from "path"; import CryptoLib, { createCryptoLib, generateAndSaveKey, loadConfig, } from "../src/core/crypto"; // Mock environment variable process.env.MASTER_KEY = crypto.randomBytes(32).toString("hex"); describe("CryptoLib", () => { let cryptoLib; const testData = { message: "Hello, World!", number: 42, array: [1, 2, 3], nested: { key: "value" }, }; beforeEach(() => { cryptoLib = new CryptoLib(); cryptoLib.initialize(); }); describe("Initialization", () => { test("default config initializes", () => { expect(cryptoLib).toBeInstanceOf(CryptoLib); }); test("custom config initializes", () => { const customCrypto = new CryptoLib({ algorithm: "chacha20-poly1305", outputEncoding: "base64", compression: true, }); customCrypto.initialize(); expect(customCrypto).toBeInstanceOf(CryptoLib); }); test("throws on unsupported algorithm", () => { expect(() => new CryptoLib({ algorithm: "unsupported" })).toThrow(); }); test("initializes with provided master key", () => { const key = CryptoLib.generateKey(); const customCrypto = new CryptoLib(); customCrypto.initialize(key); expect(customCrypto).toBeInstanceOf(CryptoLib); }); }); describe("Key Management", () => { test("generates valid key", () => { const key = CryptoLib.generateKey(); expect(Buffer.isBuffer(key)).toBe(true); expect(key.length).toBe(32); }); test("derives key from password", () => { const salt = crypto.randomBytes(16); const key = CryptoLib.deriveKey("password", salt); expect(Buffer.isBuffer(key)).toBe(true); expect(key.length).toBe(32); }); test("sets master key correctly", () => { const key = CryptoLib.generateKey(); cryptoLib.setMasterKey(key); expect(cryptoLib).toBeInstanceOf(CryptoLib); }); test("throws error on invalid key length", () => { const shortKey = crypto.randomBytes(16); expect(() => cryptoLib.setMasterKey(shortKey)).toThrow(); }); }); describe("Encryption/Decryption", () => { test("encrypt/decrypt string", async () => { const encrypted = await cryptoLib.encrypt(testData.message); const decrypted = await cryptoLib.decrypt(encrypted); expect(decrypted).toBe(testData.message); }); test("encrypt/decrypt object", async () => { const encrypted = await cryptoLib.encrypt(testData); const decrypted = await cryptoLib.decrypt(encrypted); expect(decrypted).toEqual(testData); }); test("encrypt/decrypt buffer", async () => { const buffer = Buffer.from(testData.message, "utf8"); const encrypted = await cryptoLib.encrypt(buffer); const decrypted = await cryptoLib.decrypt(encrypted, { returnBuffer: true, }); expect(Buffer.isBuffer(decrypted)).toBe(true); expect(decrypted.toString()).toBe(testData.message); }); test("handles compression", async () => { const cryptoCompressed = new CryptoLib({ compression: true }); cryptoCompressed.initialize(); const encrypted = await cryptoCompressed.encrypt(testData); const decrypted = await cryptoCompressed.decrypt(encrypted); expect(decrypted).toEqual(testData); expect(encrypted.compressed).toBe(true); }); test("handles different encodings", async () => { const cryptoBase64 = new CryptoLib({ outputEncoding: "base64" }); cryptoBase64.initialize(); const encrypted = await cryptoBase64.encrypt(testData.message); const decrypted = await cryptoBase64.decrypt(encrypted); expect(decrypted).toBe(testData.message); }); test("handles AAD", async () => { const aad = "auth-data"; const encrypted = await cryptoLib.encrypt(testData.message, { aad }); const decrypted = await cryptoLib.decrypt(encrypted, { aad }); expect(decrypted).toBe(testData.message); }); test("throws error with wrong AAD", async () => { const aad = "auth-data"; const wrongAad = "wrong"; const encrypted = await cryptoLib.encrypt(testData.message, { aad }); await expect(cryptoLib.decrypt(encrypted, { aad: wrongAad })).rejects.toThrow("Authentication failed"); }); test("stringifyResult option returns string", async () => { const encrypted = await cryptoLib.encrypt(testData.message, { stringifyResult: true, }); expect(typeof encrypted).toBe("string"); const parsed = JSON.parse(encrypted); expect(parsed).toHaveProperty("iv"); expect(parsed).toHaveProperty("tag"); expect(parsed).toHaveProperty("data"); }); test("detects tampered data", async () => { const encrypted = (await cryptoLib.encrypt(testData.message)); const tampered = { ...encrypted, data: encrypted.data.slice(0, -2) + "00", }; await expect(cryptoLib.decrypt(tampered)).rejects.toThrow("Authentication failed - data may have been tampered with"); }); }); describe("Factory Function", () => { test("createCryptoLib returns initialized instance", () => { const instance = createCryptoLib(); expect(instance).toBeInstanceOf(CryptoLib); }); }); describe("File Operations", () => { const testDir = path.join(__dirname, "test-temp"); const keyPath = path.join(testDir, "test-key.txt"); const configPath = path.join(testDir, "test-config.json"); beforeAll(async () => { await fs.mkdir(testDir, { recursive: true }); }); afterAll(async () => { await fs.rm(testDir, { recursive: true, force: true }); }); test("generate and save key", async () => { const key = await generateAndSaveKey(keyPath); expect(Buffer.isBuffer(key)).toBe(true); const saved = await fs.readFile(keyPath, "utf8"); expect(saved).toBe(key.toString("hex")); }); test("load config from JSON", async () => { const config = { masterKey: process.env.MASTER_KEY, algorithm: "aes-256-gcm", }; await fs.writeFile(configPath, JSON.stringify(config)); const loaded = await loadConfig(configPath); expect(loaded).toEqual(config); }); test("load config from text", async () => { const key = CryptoLib.generateKey().toString("hex"); await fs.writeFile(keyPath, key); const loaded = await loadConfig(keyPath); expect(loaded).toEqual({ masterKey: key }); }); test("throws error on unsupported config format", async () => { const yamlPath = path.join(testDir, "config.yaml"); await fs.writeFile(yamlPath, "key: value"); await expect(loadConfig(yamlPath)).rejects.toThrow(); }); }); describe("Error Handling", () => { test("throws when not initialized", async () => { const uninit = new CryptoLib(); await expect(uninit.encrypt("test")).rejects.toThrow("not initialized"); }); test("throws for invalid payload", async () => { const invalidPayload = { v: "1.0", algo: "aes-256-gcm", iv: "", tag: "", data: "", compressed: false, }; await expect(cryptoLib.decrypt(invalidPayload)).rejects.toThrow("Invalid payload"); }); test("throws for invalid input type", async () => { await expect(cryptoLib.encrypt(123)).rejects.toThrow("Invalid input type"); }); }); }); //# sourceMappingURL=crypto.test.js.map