flnxi-Wu/lib/__tests__/crypto-service.test.ts
2026-05-25 14:32:52 +08:00

185 lines
5.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 加密服务模块测试
* 测试 lib/license/crypto-service.ts 中的加密/解密函数
*/
import {
encryptLocal,
decryptLocal,
hashData,
generateId,
verifySignature,
verifyLicenseSignature,
} from '../license/crypto-service';
describe('本地加密/解密', () => {
it('缺少本地加密密钥时应该拒绝加密', async () => {
const originalKey = process.env.LOCAL_ENCRYPTION_KEY;
jest.resetModules();
delete process.env.LOCAL_ENCRYPTION_KEY;
const { encryptLocal: encryptWithoutKey } = await import('../license/crypto-service');
expect(() => encryptWithoutKey('secret')).toThrow('LOCAL_ENCRYPTION_KEY 未设置');
process.env.LOCAL_ENCRYPTION_KEY = originalKey;
jest.resetModules();
});
describe('encryptLocal', () => {
it('应该成功加密字符串', () => {
const plaintext = 'Hello, World!';
const encrypted = encryptLocal(plaintext);
expect(encrypted).toBeDefined();
expect(encrypted).not.toBe(plaintext);
// 格式应该是 iv:authTag:encrypted
expect(encrypted.split(':').length).toBe(3);
});
it('应该对相同输入产生不同的加密结果(因为随机 IV)', () => {
const plaintext = 'Same text';
const encrypted1 = encryptLocal(plaintext);
const encrypted2 = encryptLocal(plaintext);
expect(encrypted1).not.toBe(encrypted2);
});
it('应该能加密空字符串', () => {
const encrypted = encryptLocal('');
expect(encrypted).toBeDefined();
expect(encrypted.split(':').length).toBe(3);
});
it('应该能加密中文字符', () => {
const plaintext = '你好,世界!';
const encrypted = encryptLocal(plaintext);
expect(encrypted).toBeDefined();
});
it('应该能加密 JSON 字符串', () => {
const jsonData = JSON.stringify({ key: 'value', number: 123 });
const encrypted = encryptLocal(jsonData);
expect(encrypted).toBeDefined();
});
});
describe('decryptLocal', () => {
it('应该成功解密加密的字符串', () => {
const plaintext = 'Hello, World!';
const encrypted = encryptLocal(plaintext);
const decrypted = decryptLocal(encrypted);
expect(decrypted).toBe(plaintext);
});
it('应该成功解密中文字符', () => {
const plaintext = '你好,世界!';
const encrypted = encryptLocal(plaintext);
const decrypted = decryptLocal(encrypted);
expect(decrypted).toBe(plaintext);
});
it('应该成功解密 JSON 字符串', () => {
const jsonData = { key: 'value', number: 123, nested: { a: 1 } };
const encrypted = encryptLocal(JSON.stringify(jsonData));
const decrypted = JSON.parse(decryptLocal(encrypted));
expect(decrypted).toEqual(jsonData);
});
it('应该成功解密空字符串', () => {
const encrypted = encryptLocal('');
const decrypted = decryptLocal(encrypted);
expect(decrypted).toBe('');
});
it('解密无效数据时应该抛出错误', () => {
expect(() => decryptLocal('invalid:data:here')).toThrow('数据解密失败');
});
it('解密格式错误的数据时应该抛出错误', () => {
expect(() => decryptLocal('not-valid-format')).toThrow();
});
});
});
describe('hashData', () => {
it('应该生成 SHA-256 哈希', () => {
const data = 'test data';
const hash = hashData(data);
expect(hash).toBeDefined();
expect(hash.length).toBe(64); // SHA-256 produces 64 hex characters
});
it('相同输入应该产生相同哈希', () => {
const data = 'same data';
const hash1 = hashData(data);
const hash2 = hashData(data);
expect(hash1).toBe(hash2);
});
it('不同输入应该产生不同哈希', () => {
const hash1 = hashData('data1');
const hash2 = hashData('data2');
expect(hash1).not.toBe(hash2);
});
it('应该能哈希空字符串', () => {
const hash = hashData('');
expect(hash).toBeDefined();
expect(hash.length).toBe(64);
});
});
describe('generateId', () => {
it('应该生成 32 字符的十六进制 ID', () => {
const id = generateId();
expect(id).toBeDefined();
expect(id.length).toBe(32);
expect(/^[0-9a-f]+$/.test(id)).toBe(true);
});
it('应该生成唯一的 ID', () => {
const ids = new Set<string>();
for (let i = 0; i < 100; i++) {
ids.add(generateId());
}
expect(ids.size).toBe(100);
});
});
describe('签名验证', () => {
describe('verifySignature', () => {
it('无效签名应该返回 false', () => {
const data = 'test data';
const invalidSignature = 'invalid-signature';
const result = verifySignature(data, invalidSignature);
expect(result).toBe(false);
});
it('空签名应该返回 false', () => {
const result = verifySignature('data', '');
expect(result).toBe(false);
});
});
describe('verifyLicenseSignature', () => {
it('无效签名应该返回 false', () => {
const licenseData = { type: 'FREE', expiresAt: null };
const invalidSignature = 'invalid-signature';
const result = verifyLicenseSignature(licenseData, invalidSignature);
expect(result).toBe(false);
});
});
});