import { describe, it, expect } from 'vitest'; import { CredentialGenerator } from '../../src/credential-generator.js'; describe('CredentialGenerator', () => { describe('generatePassword', () => { it('should generate passwords meeting complexity requirements', () => { const generator = new CredentialGenerator(); const password = generator.generatePassword(); expect(password.length).toBeGreaterThanOrEqual(32); expect(/[A-Z]/.test(password)).toBe(true); expect(/[a-z]/.test(password)).toBe(true); expect(/\d/.test(password)).toBe(true); }); it('should generate unique passwords each time', () => { const generator = new CredentialGenerator(); const passwords = new Set(Array.from({ length: 100 }, () => generator.generatePassword())); expect(passwords.size).toBe(100); }); it('should respect custom length parameter', () => { const generator = new CredentialGenerator(); const password = generator.generatePassword(64); expect(password.length).toBe(64); }); it('should include special characters by default', () => { const generator = new CredentialGenerator(); const password = generator.generatePassword(); expect(/[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/.test(password)).toBe(true); }); }); describe('generateApiKey', () => { it('should generate API keys with prefix', () => { const generator = new CredentialGenerator(); const key = generator.generateApiKey('test_'); expect(key.key.startsWith('test_')).toBe(true); }); it('should generate API keys with default prefix', () => { const generator = new CredentialGenerator(); const key = generator.generateApiKey(); expect(key.key.startsWith('cf_')).toBe(true); }); it('should include keyId as UUID', () => { const generator = new CredentialGenerator(); const key = generator.generateApiKey(); expect(key.keyId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i); }); it('should include createdAt timestamp', () => { const generator = new CredentialGenerator(); const before = new Date(); const key = generator.generateApiKey(); const after = new Date(); expect(key.createdAt.getTime()).toBeGreaterThanOrEqual(before.getTime()); expect(key.createdAt.getTime()).toBeLessThanOrEqual(after.getTime()); }); it('should generate unique keys each time', () => { const generator = new CredentialGenerator(); const keys = new Set(Array.from({ length: 100 }, () => generator.generateApiKey().key)); expect(keys.size).toBe(100); }); }); describe('generateSecret', () => { it('should generate hex-encoded secrets', () => { const generator = new CredentialGenerator(); const secret = generator.generateSecret(); expect(/^[0-9a-f]+$/i.test(secret)).toBe(true); }); it('should generate secrets with default length', () => { const generator = new CredentialGenerator(); const secret = generator.generateSecret(); expect(secret.length).toBe(64); }); it('should generate secrets with custom length', () => { const generator = new CredentialGenerator(); const secret = generator.generateSecret(128); expect(secret.length).toBe(128); }); }); describe('generateEncryptionKey', () => { it('should generate 64-character hex key (32 bytes)', () => { const generator = new CredentialGenerator(); const key = generator.generateEncryptionKey(); expect(key.length).toBe(64); expect(/^[0-9a-f]+$/i.test(key)).toBe(true); }); }); describe('generateInstallationCredentials', () => { it('should generate complete credential set', () => { const generator = new CredentialGenerator(); const creds = generator.generateInstallationCredentials(); expect(creds.adminPassword).toBeDefined(); expect(creds.servicePassword).toBeDefined(); expect(creds.jwtSecret).toBeDefined(); expect(creds.sessionSecret).toBeDefined(); expect(creds.encryptionKey).toBeDefined(); expect(creds.generatedAt).toBeInstanceOf(Date); }); it('should set expiration when specified', () => { const generator = new CredentialGenerator(); const creds = generator.generateInstallationCredentials(30); expect(creds.expiresAt).toBeDefined(); const expectedExpiry = new Date(creds.generatedAt.getTime() + 30 * 24 * 60 * 60 * 1000); expect(creds.expiresAt!.getTime()).toBeCloseTo(expectedExpiry.getTime(), -3); }); }); describe('configuration validation', () => { it('should reject password length below 16', () => { expect(() => new CredentialGenerator({ passwordLength: 8 })) .toThrow('Password length must be at least 16 characters'); }); it('should reject API key length below 32', () => { expect(() => new CredentialGenerator({ apiKeyLength: 16 })) .toThrow('API key length must be at least 32 characters'); }); it('should reject secret length below 32', () => { expect(() => new CredentialGenerator({ secretLength: 16 })) .toThrow('Secret length must be at least 32 characters'); }); }); describe('utility methods', () => { it('should generate session tokens', () => { const generator = new CredentialGenerator(); const token = generator.generateSessionToken(); expect(token.length).toBe(64); }); it('should generate CSRF tokens', () => { const generator = new CredentialGenerator(); const token = generator.generateCsrfToken(); expect(token).toBeDefined(); expect(token.length).toBeGreaterThan(0); }); it('should generate nonces', () => { const generator = new CredentialGenerator(); const nonce = generator.generateNonce(); expect(nonce.length).toBe(32); expect(/^[0-9a-f]+$/i.test(nonce)).toBe(true); }); }); describe('output generation', () => { it('should create env script format', () => { const generator = new CredentialGenerator(); const creds = generator.generateInstallationCredentials(); const script = generator.createEnvScript(creds); expect(script).toContain('CLAUDE_FLOW_ADMIN_PASSWORD'); expect(script).toContain('CLAUDE_FLOW_JWT_SECRET'); expect(script).toContain('export'); }); it('should create JSON config format', () => { const generator = new CredentialGenerator(); const creds = generator.generateInstallationCredentials(); const json = generator.createJsonConfig(creds); const parsed = JSON.parse(json); expect(parsed['claude-flow/admin-password']).toBeDefined(); expect(parsed['claude-flow/jwt-secret']).toBeDefined(); }); }); });