import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as smartproxy from '../ts/index.js'; import { ProxyProtocolParser } from '../ts/core/utils/proxy-protocol.js'; tap.test('PROXY protocol v1 parser - valid headers', async () => { // Test TCP4 format const tcp4Header = Buffer.from('PROXY TCP4 192.168.1.1 10.0.0.1 56324 443\r\n', 'ascii'); const tcp4Result = ProxyProtocolParser.parse(tcp4Header); expect(tcp4Result.proxyInfo).property('protocol').toEqual('TCP4'); expect(tcp4Result.proxyInfo).property('sourceIP').toEqual('192.168.1.1'); expect(tcp4Result.proxyInfo).property('sourcePort').toEqual(56324); expect(tcp4Result.proxyInfo).property('destinationIP').toEqual('10.0.0.1'); expect(tcp4Result.proxyInfo).property('destinationPort').toEqual(443); expect(tcp4Result.remainingData.length).toEqual(0); // Test TCP6 format const tcp6Header = Buffer.from('PROXY TCP6 2001:db8::1 2001:db8::2 56324 443\r\n', 'ascii'); const tcp6Result = ProxyProtocolParser.parse(tcp6Header); expect(tcp6Result.proxyInfo).property('protocol').toEqual('TCP6'); expect(tcp6Result.proxyInfo).property('sourceIP').toEqual('2001:db8::1'); expect(tcp6Result.proxyInfo).property('sourcePort').toEqual(56324); expect(tcp6Result.proxyInfo).property('destinationIP').toEqual('2001:db8::2'); expect(tcp6Result.proxyInfo).property('destinationPort').toEqual(443); // Test UNKNOWN protocol const unknownHeader = Buffer.from('PROXY UNKNOWN\r\n', 'ascii'); const unknownResult = ProxyProtocolParser.parse(unknownHeader); expect(unknownResult.proxyInfo).property('protocol').toEqual('UNKNOWN'); expect(unknownResult.proxyInfo).property('sourceIP').toEqual(''); expect(unknownResult.proxyInfo).property('sourcePort').toEqual(0); }); tap.test('PROXY protocol v1 parser - with remaining data', async () => { const headerWithData = Buffer.concat([ Buffer.from('PROXY TCP4 192.168.1.1 10.0.0.1 56324 443\r\n', 'ascii'), Buffer.from('GET / HTTP/1.1\r\n', 'ascii') ]); const result = ProxyProtocolParser.parse(headerWithData); expect(result.proxyInfo).property('protocol').toEqual('TCP4'); expect(result.proxyInfo).property('sourceIP').toEqual('192.168.1.1'); expect(result.remainingData.toString()).toEqual('GET / HTTP/1.1\r\n'); }); tap.test('PROXY protocol v1 parser - invalid headers', async () => { // Not a PROXY protocol header const notProxy = Buffer.from('GET / HTTP/1.1\r\n', 'ascii'); const notProxyResult = ProxyProtocolParser.parse(notProxy); expect(notProxyResult.proxyInfo).toBeNull(); expect(notProxyResult.remainingData).toEqual(notProxy); // Invalid protocol expect(() => { ProxyProtocolParser.parse(Buffer.from('PROXY INVALID 1.1.1.1 2.2.2.2 80 443\r\n', 'ascii')); }).toThrow(); // Wrong number of fields expect(() => { ProxyProtocolParser.parse(Buffer.from('PROXY TCP4 192.168.1.1 10.0.0.1 56324\r\n', 'ascii')); }).toThrow(); // Invalid port expect(() => { ProxyProtocolParser.parse(Buffer.from('PROXY TCP4 192.168.1.1 10.0.0.1 99999 443\r\n', 'ascii')); }).toThrow(); // Invalid IP for protocol expect(() => { ProxyProtocolParser.parse(Buffer.from('PROXY TCP4 2001:db8::1 10.0.0.1 56324 443\r\n', 'ascii')); }).toThrow(); }); tap.test('PROXY protocol v1 parser - incomplete headers', async () => { // Header without terminator const incomplete = Buffer.from('PROXY TCP4 192.168.1.1 10.0.0.1 56324 443', 'ascii'); const result = ProxyProtocolParser.parse(incomplete); expect(result.proxyInfo).toBeNull(); expect(result.remainingData).toEqual(incomplete); // Header exceeding max length - create a buffer that actually starts with PROXY const longHeader = Buffer.from('PROXY TCP4 ' + '1'.repeat(100), 'ascii'); expect(() => { ProxyProtocolParser.parse(longHeader); }).toThrow(); }); tap.test('PROXY protocol v1 generator', async () => { // Generate TCP4 header const tcp4Info = { protocol: 'TCP4' as const, sourceIP: '192.168.1.1', sourcePort: 56324, destinationIP: '10.0.0.1', destinationPort: 443 }; const tcp4Header = ProxyProtocolParser.generate(tcp4Info); expect(tcp4Header.toString('ascii')).toEqual('PROXY TCP4 192.168.1.1 10.0.0.1 56324 443\r\n'); // Generate TCP6 header const tcp6Info = { protocol: 'TCP6' as const, sourceIP: '2001:db8::1', sourcePort: 56324, destinationIP: '2001:db8::2', destinationPort: 443 }; const tcp6Header = ProxyProtocolParser.generate(tcp6Info); expect(tcp6Header.toString('ascii')).toEqual('PROXY TCP6 2001:db8::1 2001:db8::2 56324 443\r\n'); // Generate UNKNOWN header const unknownInfo = { protocol: 'UNKNOWN' as const, sourceIP: '', sourcePort: 0, destinationIP: '', destinationPort: 0 }; const unknownHeader = ProxyProtocolParser.generate(unknownInfo); expect(unknownHeader.toString('ascii')).toEqual('PROXY UNKNOWN\r\n'); }); // Skipping integration tests for now - focus on unit tests // Integration tests would require more complex setup and teardown tap.start();