/** * Comprehensive TLS Connection Test Suite * Tests all aspects of raw TLS S2S connection establishment */ import * as tls from 'tls'; import * as crypto from 'crypto'; import * as fs from 'fs'; import { TLSClient, TLSConnection } from '@/transport/tls-client/tls-client'; import { receiverConfig } from '@/config/receiver-config'; describe('TLS Connection Tests', () => { const RECEIVER_IP = '172.67.157.88'; const RECEIVER_PORT = 443; const RECEIVER_PORT_ALT = 8443; const RECEIVER_SNI = 'devmindgroup.com'; const EXPECTED_SHA256_FINGERPRINT = 'b19f2a94eab4cd3b92f1e3e0dce9d5e41c8b7aa3fdbe6e2f4ac3c91a5fbb2f44'; describe('Connection Parameters', () => { it('should have correct receiver IP configured', () => { expect(receiverConfig.ip).toBe(RECEIVER_IP); }); it('should have correct receiver port configured', () => { expect(receiverConfig.port).toBe(RECEIVER_PORT); }); it('should have correct SNI configured', () => { expect(receiverConfig.sni).toBe(RECEIVER_SNI); }); it('should have TLS version configured', () => { expect(receiverConfig.tlsVersion).toBeDefined(); expect(['TLSv1.2', 'TLSv1.3']).toContain(receiverConfig.tlsVersion); }); it('should have length-prefix framing configured', () => { expect(receiverConfig.framing).toBe('length-prefix-4be'); }); }); describe('Raw TLS Socket Connection', () => { let tlsClient: TLSClient; let connection: TLSConnection | null = null; beforeEach(() => { tlsClient = new TLSClient(); }); afterEach(async () => { if (connection) { await tlsClient.close(); connection = null; } }); it('should establish TLS connection to receiver IP', async () => { connection = await tlsClient.connect(); expect(connection).toBeDefined(); expect(connection.connected).toBe(true); expect(connection.socket).toBeDefined(); expect(connection.sessionId).toBeDefined(); }, 60000); // 60 second timeout for network operations it('should use correct SNI in TLS handshake', async () => { const tlsOptions: tls.ConnectionOptions = { host: RECEIVER_IP, port: RECEIVER_PORT, servername: RECEIVER_SNI, rejectUnauthorized: false, // For testing only }; await new Promise((resolve, reject) => { const socket = tls.connect(tlsOptions, () => { const servername = (socket as any).servername; expect(servername).toBe(RECEIVER_SNI); socket.end(); resolve(); }); socket.on('error', reject); socket.setTimeout(30000); socket.on('timeout', () => { socket.destroy(); reject(new Error('Connection timeout')); }); }); }, 60000); it('should verify server certificate SHA256 fingerprint', async () => { const tlsOptions: tls.ConnectionOptions = { host: RECEIVER_IP, port: RECEIVER_PORT, servername: RECEIVER_SNI, rejectUnauthorized: false, // We'll verify manually }; await new Promise((resolve, reject) => { const socket = tls.connect(tlsOptions, () => { try { const cert = socket.getPeerCertificate(true); if (cert && cert.raw) { const fingerprint = crypto .createHash('sha256') .update(cert.raw) .digest('hex') .toLowerCase(); expect(fingerprint).toBe(EXPECTED_SHA256_FINGERPRINT.toLowerCase()); socket.end(); resolve(); } else { reject(new Error('Certificate not available')); } } catch (error) { reject(error); } }); socket.on('error', reject); socket.setTimeout(30000); socket.on('timeout', () => { socket.destroy(); reject(new Error('Connection timeout')); }); }); }, 60000); it('should use TLSv1.2 or higher', async () => { connection = await tlsClient.connect(); const protocol = connection.socket.getProtocol(); expect(protocol).toBeDefined(); expect(['TLSv1.2', 'TLSv1.3']).toContain(protocol); }, 60000); it('should handle connection to alternate port 8443', async () => { const tlsOptions: tls.ConnectionOptions = { host: RECEIVER_IP, port: RECEIVER_PORT_ALT, servername: RECEIVER_SNI, rejectUnauthorized: false, minVersion: 'TLSv1.2', }; await new Promise((resolve) => { const socket = tls.connect(tlsOptions, () => { expect(socket.authorized || true).toBeDefined(); // May or may not be authorized socket.end(); resolve(); }); socket.on('error', (error) => { // Port might not be available, that's okay for testing console.warn(`Port ${RECEIVER_PORT_ALT} connection test:`, error.message); resolve(); // Don't fail if port is not available }); socket.setTimeout(30000); socket.on('timeout', () => { socket.destroy(); resolve(); // Don't fail on timeout for alternate port }); }); }, 60000); it('should record TLS session with fingerprint', async () => { connection = await tlsClient.connect(); expect(connection.fingerprint).toBeDefined(); expect(connection.fingerprint.length).toBeGreaterThan(0); expect(connection.sessionId).toBeDefined(); expect(connection.sessionId.length).toBeGreaterThan(0); }, 60000); it('should handle connection errors gracefully', async () => { const invalidTlsClient = new TLSClient(); // Temporarily override config to use invalid IP const originalIp = receiverConfig.ip; (receiverConfig as any).ip = '192.0.2.1'; // Invalid test IP try { await expect(invalidTlsClient.connect()).rejects.toThrow(); } finally { (receiverConfig as any).ip = originalIp; await invalidTlsClient.close(); } }, 30000); it('should timeout after configured timeout period', async () => { const timeoutClient = new TLSClient(); const originalIp = receiverConfig.ip; (receiverConfig as any).ip = '10.255.255.1'; // Unreachable IP try { await expect(timeoutClient.connect()).rejects.toThrow(); } finally { (receiverConfig as any).ip = originalIp; await timeoutClient.close(); } }, 35000); }); describe('Mutual TLS (mTLS)', () => { it('should support client certificate if configured', () => { // Check if mTLS paths are configured if (receiverConfig.clientCertPath && receiverConfig.clientKeyPath) { expect(fs.existsSync(receiverConfig.clientCertPath)).toBe(true); expect(fs.existsSync(receiverConfig.clientKeyPath)).toBe(true); } }); it('should support CA certificate bundle if configured', () => { if (receiverConfig.caCertPath) { expect(fs.existsSync(receiverConfig.caCertPath)).toBe(true); } }); }); describe('Connection Reuse', () => { let tlsClient: TLSClient; beforeEach(() => { tlsClient = new TLSClient(); }); afterEach(async () => { await tlsClient.close(); }); it('should reuse existing connection if available', async () => { const connection1 = await tlsClient.connect(); const connection2 = await tlsClient.connect(); expect(connection1.sessionId).toBe(connection2.sessionId); expect(connection1.socket).toBe(connection2.socket); }, 60000); it('should create new connection if previous one closed', async () => { const connection1 = await tlsClient.connect(); const sessionId1 = connection1.sessionId; await tlsClient.close(); const connection2 = await tlsClient.connect(); const sessionId2 = connection2.sessionId; expect(sessionId1).not.toBe(sessionId2); }, 60000); }); });