Files
calendar/packages/lib/crypto.test.ts
T
Keith WilliamsGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
20c67ef101 fix: handle non-deterministic AES-256-CBC decryption in crypto test (#26383)
AES-256-CBC doesn't guarantee throwing on wrong key decryption - it depends
on whether the decrypted bytes happen to have valid PKCS#7 padding. The test
now verifies that decryption either throws OR returns a value different from
the original plaintext.

This fixes flaky test failures that started appearing after the Vitest 4.0
upgrade, where the 'Closing rpc while fetch was pending' error was a secondary
symptom of the test failure causing worker teardown during module loading.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 23:18:35 -03:00

105 lines
3.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { symmetricDecrypt, symmetricEncrypt } from "./crypto";
describe("crypto", () => {
const testKey = "12345678901234567890123456789012"; // 32 bytes key
const testText = "Hello, World!";
describe("symmetricEncrypt", () => {
it("should encrypt text with a valid key", () => {
const encrypted = symmetricEncrypt(testText, testKey);
// Verify the format is "iv:ciphertext"
expect(encrypted).toContain(":");
const [iv, ciphertext] = encrypted.split(":");
// IV should be 32 characters (16 bytes in hex)
expect(iv).toHaveLength(32);
// Ciphertext should exist
expect(ciphertext).toBeDefined();
expect(ciphertext.length).toBeGreaterThan(0);
});
it("should produce different ciphertexts for the same input due to random IV", () => {
const encrypted1 = symmetricEncrypt(testText, testKey);
const encrypted2 = symmetricEncrypt(testText, testKey);
expect(encrypted1).not.toBe(encrypted2);
});
it("should throw error if key is not 32 bytes", () => {
const shortKey = "short";
expect(() => symmetricEncrypt(testText, shortKey)).toThrow();
});
});
describe("symmetricDecrypt", () => {
it("should correctly decrypt encrypted text", () => {
const encrypted = symmetricEncrypt(testText, testKey);
const decrypted = symmetricDecrypt(encrypted, testKey);
expect(decrypted).toBe(testText);
});
it("should throw error for malformed encrypted text", () => {
// Test with invalid IV:ciphertext format
expect(() => symmetricDecrypt("invalid", testKey)).toThrow();
expect(() => symmetricDecrypt("invalid:data", testKey)).toThrow();
expect(() => symmetricDecrypt(":", testKey)).toThrow();
});
it("should fail to decrypt correctly if wrong key is used", () => {
const encrypted = symmetricEncrypt(testText, testKey);
const wrongKey = "12345678901234567890123456789013"; // Different 32 bytes key
// AES-256-CBC doesn't guarantee throwing on wrong key - it depends on whether
// the decrypted bytes happen to have valid PKCS#7 padding. The test verifies
// that decryption either throws OR returns a value different from the original.
let decryptedWithWrongKey: string | null = null;
let threwError = false;
try {
decryptedWithWrongKey = symmetricDecrypt(encrypted, wrongKey);
} catch {
threwError = true;
}
// Either it threw an error, or the decrypted value is not the original text
expect(threwError || decryptedWithWrongKey !== testText).toBe(true);
});
it("should handle empty string encryption/decryption", () => {
const emptyText = "";
const encrypted = symmetricEncrypt(emptyText, testKey);
const decrypted = symmetricDecrypt(encrypted, testKey);
expect(decrypted).toBe(emptyText);
});
it("should handle long text encryption/decryption", () => {
const longText = "a".repeat(1000);
const encrypted = symmetricEncrypt(longText, testKey);
const decrypted = symmetricDecrypt(encrypted, testKey);
expect(decrypted).toBe(longText);
});
it("should handle special characters", () => {
const specialChars = "!@#$%^&*()_+-=[]{}|;:'\",.<>?/\\`~";
const encrypted = symmetricEncrypt(specialChars, testKey);
const decrypted = symmetricDecrypt(encrypted, testKey);
expect(decrypted).toBe(specialChars);
});
it("should handle unicode characters", () => {
const unicodeText = "Hello, 世界! 👋 🌍";
const encrypted = symmetricEncrypt(unicodeText, testKey);
const decrypted = symmetricDecrypt(encrypted, testKey);
expect(decrypted).toBe(unicodeText);
});
});
});