import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as net from 'net'; import * as tls from 'tls'; import * as fs from 'fs'; import * as path from 'path'; import { SmartProxy } from '../ts/proxies/smart-proxy/smart-proxy.js'; import type { IRouteConfig } from '../ts/proxies/smart-proxy/models/route-types.js'; // Setup test infrastructure const testCertPath = path.join(process.cwd(), 'test', 'helpers', 'test-cert.pem'); const testKeyPath = path.join(process.cwd(), 'test', 'helpers', 'test-key.pem'); let testServer: net.Server; let tlsTestServer: tls.Server; let smartProxy: SmartProxy; tap.test('setup test servers', async () => { // Create TCP test server testServer = net.createServer((socket) => { socket.write('Connected to TCP test server\n'); socket.on('data', (data) => { socket.write(`TCP Echo: ${data}`); }); }); await new Promise((resolve) => { testServer.listen(7001, '127.0.0.1', () => { console.log('TCP test server listening on port 7001'); resolve(); }); }); // Create TLS test server for SNI testing tlsTestServer = tls.createServer( { cert: fs.readFileSync(testCertPath), key: fs.readFileSync(testKeyPath), }, (socket) => { socket.write('Connected to TLS test server\n'); socket.on('data', (data) => { socket.write(`TLS Echo: ${data}`); }); } ); await new Promise((resolve) => { tlsTestServer.listen(7002, '127.0.0.1', () => { console.log('TLS test server listening on port 7002'); resolve(); }); }); }); tap.test('should forward TCP connections correctly', async () => { // Create SmartProxy with forward route smartProxy = new SmartProxy({ enableDetailedLogging: true, routes: [ { id: 'tcp-forward', name: 'TCP Forward Route', match: { ports: 8080, }, action: { type: 'forward', target: { host: '127.0.0.1', port: 7001, }, }, }, ], }); await smartProxy.start(); // Test TCP forwarding const client = await new Promise((resolve, reject) => { const socket = net.connect(8080, '127.0.0.1', () => { console.log('Connected to proxy'); resolve(socket); }); socket.on('error', reject); }); // Test data transmission await new Promise((resolve) => { client.on('data', (data) => { const response = data.toString(); console.log('Received:', response); expect(response).toContain('Connected to TCP test server'); client.end(); resolve(); }); client.write('Hello from client'); }); await smartProxy.stop(); }); tap.test('should handle TLS passthrough correctly', async () => { // Create SmartProxy with TLS passthrough route smartProxy = new SmartProxy({ enableDetailedLogging: true, routes: [ { id: 'tls-passthrough', name: 'TLS Passthrough Route', match: { ports: 8443, domains: 'test.example.com', }, action: { type: 'forward', tls: { mode: 'passthrough', }, target: { host: '127.0.0.1', port: 7002, }, }, }, ], }); await smartProxy.start(); // Test TLS passthrough const client = await new Promise((resolve, reject) => { const socket = tls.connect( { port: 8443, host: '127.0.0.1', servername: 'test.example.com', rejectUnauthorized: false, }, () => { console.log('Connected via TLS'); resolve(socket); } ); socket.on('error', reject); }); // Test data transmission over TLS await new Promise((resolve) => { client.on('data', (data) => { const response = data.toString(); console.log('TLS Received:', response); expect(response).toContain('Connected to TLS test server'); client.end(); resolve(); }); client.write('Hello from TLS client'); }); await smartProxy.stop(); }); tap.test('should handle SNI-based forwarding', async () => { // Create SmartProxy with multiple domain routes smartProxy = new SmartProxy({ enableDetailedLogging: true, routes: [ { id: 'domain-a', name: 'Domain A Route', match: { ports: 8443, domains: 'a.example.com', }, action: { type: 'forward', tls: { mode: 'passthrough', }, target: { host: '127.0.0.1', port: 7002, }, }, }, { id: 'domain-b', name: 'Domain B Route', match: { ports: 8443, domains: 'b.example.com', }, action: { type: 'forward', target: { host: '127.0.0.1', port: 7001, }, }, }, ], }); await smartProxy.start(); // Test domain A (TLS passthrough) const clientA = await new Promise((resolve, reject) => { const socket = tls.connect( { port: 8443, host: '127.0.0.1', servername: 'a.example.com', rejectUnauthorized: false, }, () => { console.log('Connected to domain A'); resolve(socket); } ); socket.on('error', reject); }); await new Promise((resolve) => { clientA.on('data', (data) => { const response = data.toString(); console.log('Domain A response:', response); expect(response).toContain('Connected to TLS test server'); clientA.end(); resolve(); }); clientA.write('Hello from domain A'); }); // Test domain B (non-TLS forward) const clientB = await new Promise((resolve, reject) => { const socket = net.connect(8443, '127.0.0.1', () => { // Send TLS ClientHello with SNI for b.example.com const clientHello = Buffer.from([ 0x16, 0x03, 0x01, 0x00, 0x4e, // TLS Record header 0x01, 0x00, 0x00, 0x4a, // Handshake header 0x03, 0x03, // TLS version // Random bytes ...Array(32).fill(0), 0x00, // Session ID length 0x00, 0x02, // Cipher suites length 0x00, 0x35, // Cipher suite 0x01, 0x00, // Compression methods 0x00, 0x1f, // Extensions length 0x00, 0x00, // SNI extension 0x00, 0x1b, // Extension length 0x00, 0x19, // SNI list length 0x00, // SNI type (hostname) 0x00, 0x16, // SNI length // "b.example.com" in ASCII 0x62, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, ]); socket.write(clientHello); setTimeout(() => { resolve(socket); }, 100); }); socket.on('error', reject); }); await new Promise((resolve) => { clientB.on('data', (data) => { const response = data.toString(); console.log('Domain B response:', response); // Should be forwarded to TCP server expect(response).toContain('Connected to TCP test server'); clientB.end(); resolve(); }); // Send regular data after initial handshake setTimeout(() => { clientB.write('Hello from domain B'); }, 200); }); await smartProxy.stop(); }); tap.test('cleanup', async () => { testServer.close(); tlsTestServer.close(); }); export default tap.start();