fix: remove nested .git folders, re-add as normal directories
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
import { describe, test, expect } from "bun:test";
|
||||
import { generateSecureValue } from "../../src/modules/credentials/generateSecureValue";
|
||||
import { readSecureValue } from "../../src/modules/credentials/readSecureValue";
|
||||
|
||||
/**
|
||||
* Tests for the secure value encryption/decryption round-trip.
|
||||
*
|
||||
* The test setup.ts mocks the constants module with a matching RSA key pair,
|
||||
* so generateSecureValue (uses public key) and readSecureValue (uses private key)
|
||||
* will work correctly together.
|
||||
*/
|
||||
|
||||
describe("generateSecureValue", () => {
|
||||
test("returns an object with encrypted and hash fields", () => {
|
||||
const result = generateSecureValue("my-secret-password");
|
||||
expect(result).toHaveProperty("encrypted");
|
||||
expect(result).toHaveProperty("hash");
|
||||
expect(typeof result.encrypted).toBe("string");
|
||||
expect(typeof result.hash).toBe("string");
|
||||
});
|
||||
|
||||
test("encrypted is a valid base64 string", () => {
|
||||
const result = generateSecureValue("test-value");
|
||||
expect(() => Buffer.from(result.encrypted, "base64")).not.toThrow();
|
||||
const decoded = Buffer.from(result.encrypted, "base64");
|
||||
expect(decoded.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("hash follows BLAKE2s format", () => {
|
||||
const result = generateSecureValue("test-value");
|
||||
expect(result.hash).toMatch(/^BLAKE2s\$/);
|
||||
const parts = result.hash.split("$");
|
||||
expect(parts[0]).toBe("BLAKE2s");
|
||||
expect(parts[1].length).toBeGreaterThan(0); // hex hash
|
||||
});
|
||||
|
||||
test("different inputs produce different encrypted values", () => {
|
||||
const a = generateSecureValue("password-a");
|
||||
const b = generateSecureValue("password-b");
|
||||
expect(a.encrypted).not.toBe(b.encrypted);
|
||||
});
|
||||
|
||||
test("different inputs produce different hashes", () => {
|
||||
const a = generateSecureValue("password-a");
|
||||
const b = generateSecureValue("password-b");
|
||||
expect(a.hash).not.toBe(b.hash);
|
||||
});
|
||||
|
||||
test("encrypts empty string without error", () => {
|
||||
const result = generateSecureValue("");
|
||||
expect(result.encrypted.length).toBeGreaterThan(0);
|
||||
expect(result.hash.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("encrypts special characters", () => {
|
||||
const result = generateSecureValue('p@$$w0rd!#%^&*(){}[]|\\:";<>?,./~`');
|
||||
expect(result.encrypted.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("encrypts Unicode content", () => {
|
||||
const result = generateSecureValue("密码测试 🔐");
|
||||
expect(result.encrypted.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("readSecureValue", () => {
|
||||
test("decrypts a value encrypted by generateSecureValue", () => {
|
||||
const original = "my-secret-password";
|
||||
const { encrypted } = generateSecureValue(original);
|
||||
const decrypted = readSecureValue(encrypted);
|
||||
expect(decrypted).toBe(original);
|
||||
});
|
||||
|
||||
test("decrypts empty string", () => {
|
||||
const { encrypted } = generateSecureValue("");
|
||||
const decrypted = readSecureValue(encrypted);
|
||||
expect(decrypted).toBe("");
|
||||
});
|
||||
|
||||
test("decrypts special characters", () => {
|
||||
const original = 'p@$$w0rd!#%^&*(){}[]|\\:";<>?,./~`';
|
||||
const { encrypted } = generateSecureValue(original);
|
||||
const decrypted = readSecureValue(encrypted);
|
||||
expect(decrypted).toBe(original);
|
||||
});
|
||||
|
||||
test("decrypts Unicode content", () => {
|
||||
const original = "密码测试 🔐";
|
||||
const { encrypted } = generateSecureValue(original);
|
||||
const decrypted = readSecureValue(encrypted);
|
||||
expect(decrypted).toBe(original);
|
||||
});
|
||||
|
||||
test("validates hash when provided and correct", () => {
|
||||
const original = "test-value";
|
||||
const { encrypted, hash } = generateSecureValue(original);
|
||||
const decrypted = readSecureValue(encrypted, hash);
|
||||
expect(decrypted).toBe(original);
|
||||
});
|
||||
|
||||
test("throws when hash validation fails", () => {
|
||||
const original = "test-value";
|
||||
const { encrypted } = generateSecureValue(original);
|
||||
const badHash =
|
||||
"BLAKE2s$0000000000000000000000000000000000000000000000000000000000000000$salt";
|
||||
expect(() => readSecureValue(encrypted, badHash)).toThrow(
|
||||
"Secure value hash validation failed",
|
||||
);
|
||||
});
|
||||
|
||||
test("throws GenericError on invalid encrypted content", () => {
|
||||
try {
|
||||
readSecureValue("not-valid-encrypted-data");
|
||||
expect(true).toBe(false); // should not reach
|
||||
} catch (e: any) {
|
||||
expect(e.name).toBe("SecureValueDecryptionError");
|
||||
expect(e.status).toBe(422);
|
||||
}
|
||||
});
|
||||
|
||||
test("throws GenericError with descriptive message on key mismatch", () => {
|
||||
try {
|
||||
readSecureValue("dGhpcyBpcyBub3QgZW5jcnlwdGVk"); // base64 but not RSA
|
||||
expect(true).toBe(false);
|
||||
} catch (e: any) {
|
||||
expect(e.message).toContain("Unable to decrypt secure value");
|
||||
expect(e.cause).toContain("RSA key mismatch");
|
||||
}
|
||||
});
|
||||
|
||||
test("skips hash validation when hash is not provided", () => {
|
||||
const original = "no-hash-check";
|
||||
const { encrypted } = generateSecureValue(original);
|
||||
// Should not throw even though no hash is passed
|
||||
const decrypted = readSecureValue(encrypted);
|
||||
expect(decrypted).toBe(original);
|
||||
});
|
||||
});
|
||||
|
||||
describe("generateSecureValue + readSecureValue round-trip", () => {
|
||||
test("round-trips various string types", () => {
|
||||
const testValues = [
|
||||
"simple",
|
||||
"",
|
||||
"a".repeat(100),
|
||||
"line1\nline2\ttab",
|
||||
'{"json": true}',
|
||||
"null",
|
||||
"undefined",
|
||||
"0",
|
||||
" leading-trailing ",
|
||||
];
|
||||
|
||||
for (const original of testValues) {
|
||||
const { encrypted, hash } = generateSecureValue(original);
|
||||
const decrypted = readSecureValue(encrypted, hash);
|
||||
expect(decrypted).toBe(original);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user