tl-shared-security
Version:
Enterprise-grade security module for frontend and backend applications with comprehensive protection against XSS, CSRF, SQL injection, and other security vulnerabilities
219 lines • 10.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const crypto_service_1 = require("./crypto.service");
describe('CryptoService', () => {
let service;
beforeEach(() => {
service = new crypto_service_1.CryptoService();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('encrypt/decrypt', () => {
it('should encrypt and decrypt data correctly', () => {
const data = 'Hello, World!';
const password = 'test-password';
const encrypted = service.encrypt(data, password);
expect(encrypted).toBeDefined();
expect(encrypted).not.toBe(data);
expect(encrypted.split(':').length).toBe(4); // iv:salt:authTag:encryptedData
const decrypted = service.decrypt(encrypted, password);
expect(decrypted).toBe(data);
});
it('should encrypt same data differently each time', () => {
const data = 'Hello, World!';
const password = 'test-password';
const encrypted1 = service.encrypt(data, password);
const encrypted2 = service.encrypt(data, password);
expect(encrypted1).not.toBe(encrypted2);
expect(service.decrypt(encrypted1, password)).toBe(data);
expect(service.decrypt(encrypted2, password)).toBe(data);
});
it('should fail to decrypt with wrong password', () => {
const data = 'Hello, World!';
const password = 'test-password';
const wrongPassword = 'wrong-password';
const encrypted = service.encrypt(data, password);
expect(() => {
service.decrypt(encrypted, wrongPassword);
}).toThrow();
});
it('should fail to decrypt malformed data', () => {
const password = 'test-password';
expect(() => {
service.decrypt('invalid-format', password);
}).toThrow('Invalid encrypted data format');
});
it('should handle empty data', () => {
const data = '';
const password = 'test-password';
const encrypted = service.encrypt(data, password);
const decrypted = service.decrypt(encrypted, password);
expect(decrypted).toBe(data);
});
it('should handle unicode data', () => {
const data = '🔐 Unicode test with émojis and spëcial chars 中文';
const password = 'test-password';
const encrypted = service.encrypt(data, password);
const decrypted = service.decrypt(encrypted, password);
expect(decrypted).toBe(data);
});
});
describe('hashPassword/verifyPassword (bcrypt)', () => {
it('should hash and verify password correctly', () => {
const password = 'test-password';
const hashed = service.hashPassword(password);
expect(hashed).toBeDefined();
expect(hashed).not.toBe(password);
expect(hashed.startsWith('$2b$')).toBe(true); // bcrypt format
const isValid = service.verifyPassword(password, hashed);
expect(isValid).toBe(true);
});
it('should hash same password differently each time', () => {
const password = 'test-password';
const hashed1 = service.hashPassword(password);
const hashed2 = service.hashPassword(password);
expect(hashed1).not.toBe(hashed2);
expect(service.verifyPassword(password, hashed1)).toBe(true);
expect(service.verifyPassword(password, hashed2)).toBe(true);
});
it('should fail to verify with wrong password', () => {
const password = 'test-password';
const wrongPassword = 'wrong-password';
const hashed = service.hashPassword(password);
const isValid = service.verifyPassword(wrongPassword, hashed);
expect(isValid).toBe(false);
});
it('should handle different salt rounds', () => {
const password = 'test-password';
const hashed10 = service.hashPassword(password, 10);
const hashed12 = service.hashPassword(password, 12);
expect(service.verifyPassword(password, hashed10)).toBe(true);
expect(service.verifyPassword(password, hashed12)).toBe(true);
});
it('should work with async methods', async () => {
const password = 'test-password';
const hashed = await service.hashPasswordAsync(password);
expect(hashed).toBeDefined();
expect(hashed.startsWith('$2b$')).toBe(true);
const isValid = await service.verifyPasswordAsync(password, hashed);
expect(isValid).toBe(true);
const isInvalid = await service.verifyPasswordAsync('wrong', hashed);
expect(isInvalid).toBe(false);
});
it('should fallback to PBKDF2 for legacy hashes', () => {
const password = 'test-password';
// Create PBKDF2 hash
const pbkdf2Hash = service.hashPasswordPBKDF2(password);
expect(pbkdf2Hash.split(':').length).toBe(3); // salt:iterations:hash
// Should verify with main method (fallback)
const isValid = service.verifyPassword(password, pbkdf2Hash);
expect(isValid).toBe(true);
});
});
describe('generateToken', () => {
it('should generate random tokens', () => {
const token1 = service.generateToken();
const token2 = service.generateToken();
expect(token1).toBeDefined();
expect(token2).toBeDefined();
expect(token1).not.toBe(token2);
expect(token1.length).toBe(64); // 32 bytes * 2 (hex)
});
it('should generate tokens of specified length', () => {
const token = service.generateToken(16);
expect(token.length).toBe(32); // 16 bytes * 2 (hex)
});
it('should generate cryptographically secure tokens', () => {
const tokens = new Set();
// Generate 1000 tokens and ensure they're all unique
for (let i = 0; i < 1000; i++) {
tokens.add(service.generateToken());
}
expect(tokens.size).toBe(1000);
});
});
describe('sign/verifySignature', () => {
it('should sign and verify data correctly', () => {
const data = 'Hello, World!';
const secret = 'test-secret';
const signature = service.sign(data, secret);
expect(signature).toBeDefined();
expect(signature.length).toBe(64); // SHA256 hex = 64 chars
const isValid = service.verifySignature(data, signature, secret);
expect(isValid).toBe(true);
});
it('should generate same signature for same data', () => {
const data = 'Hello, World!';
const secret = 'test-secret';
const signature1 = service.sign(data, secret);
const signature2 = service.sign(data, secret);
expect(signature1).toBe(signature2);
});
it('should fail to verify with wrong secret', () => {
const data = 'Hello, World!';
const secret = 'test-secret';
const wrongSecret = 'wrong-secret';
const signature = service.sign(data, secret);
const isValid = service.verifySignature(data, signature, wrongSecret);
expect(isValid).toBe(false);
});
it('should fail to verify with wrong data', () => {
const data = 'Hello, World!';
const wrongData = 'Wrong data';
const secret = 'test-secret';
const signature = service.sign(data, secret);
const isValid = service.verifySignature(wrongData, signature, secret);
expect(isValid).toBe(false);
});
it('should handle different algorithms', () => {
const data = 'Hello, World!';
const secret = 'test-secret';
const sha256Sig = service.sign(data, secret, { algorithm: 'sha256' });
const sha512Sig = service.sign(data, secret, { algorithm: 'sha512' });
expect(sha256Sig).not.toBe(sha512Sig);
expect(service.verifySignature(data, sha256Sig, secret, { algorithm: 'sha256' })).toBe(true);
expect(service.verifySignature(data, sha512Sig, secret, { algorithm: 'sha512' })).toBe(true);
});
});
describe('generateSecureRandomString', () => {
it('should generate random strings with different encodings', () => {
const hexString = service.generateSecureRandomString(16, 'hex');
const base64String = service.generateSecureRandomString(16, 'base64');
expect(hexString.length).toBe(32); // 16 bytes * 2
expect(base64String.length).toBe(24); // Base64 encoding
expect(/^[0-9a-f]+$/.test(hexString)).toBe(true);
});
});
describe('generateUUID', () => {
it('should generate valid UUIDs', () => {
const uuid1 = service.generateUUID();
const uuid2 = service.generateUUID();
expect(uuid1).not.toBe(uuid2);
expect(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid1)).toBe(true);
expect(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid2)).toBe(true);
});
});
describe('performance and security', () => {
it('should handle large data encryption efficiently', () => {
const largeData = 'x'.repeat(10000);
const password = 'test-password';
const start = Date.now();
const encrypted = service.encrypt(largeData, password);
const decrypted = service.decrypt(encrypted, password);
const end = Date.now();
expect(decrypted).toBe(largeData);
expect(end - start).toBeLessThan(1000); // Should complete within 1 second
});
it('should use timing-safe comparison for signatures', () => {
const data = 'Hello, World!';
const secret = 'test-secret';
const signature = service.sign(data, secret);
// This test ensures timing-safe comparison is used
// by verifying that wrong signatures of same length are handled correctly
const wrongSignature = 'a'.repeat(signature.length);
expect(service.verifySignature(data, wrongSignature, secret)).toBe(false);
});
});
});
//# sourceMappingURL=crypto.service.spec.js.map