import { expect, tap } from '@git.zone/tstest/tapbundle'; import { SecurityManager } from '../ts/proxies/http-proxy/security-manager.js'; import { createLogger } from '../ts/proxies/http-proxy/models/types.js'; let securityManager: SecurityManager; const logger = createLogger('error'); // Quiet logger for tests tap.test('Setup HttpProxy SecurityManager', async () => { securityManager = new SecurityManager(logger, [], 3, 10); // Low limits for testing }); tap.test('HttpProxy IP connection tracking', async () => { const testIP = '10.0.0.1'; // Track connections securityManager.trackConnectionByIP(testIP, 'http-conn1'); securityManager.trackConnectionByIP(testIP, 'http-conn2'); expect(securityManager.getConnectionCountByIP(testIP)).toEqual(2); // Validate IP should pass let result = securityManager.validateIP(testIP); expect(result.allowed).toBeTrue(); // Add one more to reach limit securityManager.trackConnectionByIP(testIP, 'http-conn3'); // Should now reject new connections result = securityManager.validateIP(testIP); expect(result.allowed).toBeFalse(); expect(result.reason).toInclude('Maximum connections per IP (3) exceeded'); // Remove a connection securityManager.removeConnectionByIP(testIP, 'http-conn1'); // Should allow connections again result = securityManager.validateIP(testIP); expect(result.allowed).toBeTrue(); // Clean up securityManager.removeConnectionByIP(testIP, 'http-conn2'); securityManager.removeConnectionByIP(testIP, 'http-conn3'); }); tap.test('HttpProxy connection rate limiting', async () => { const testIP = '10.0.0.2'; // Make 10 connections rapidly (at rate limit) for (let i = 0; i < 10; i++) { const result = securityManager.validateIP(testIP); expect(result.allowed).toBeTrue(); // Track the connection to simulate real usage securityManager.trackConnectionByIP(testIP, `rate-conn${i}`); } // 11th connection should be rate limited const result = securityManager.validateIP(testIP); expect(result.allowed).toBeFalse(); expect(result.reason).toInclude('Connection rate limit (10/min) exceeded'); // Clean up for (let i = 0; i < 10; i++) { securityManager.removeConnectionByIP(testIP, `rate-conn${i}`); } }); tap.test('HttpProxy CLIENT_IP header handling', async () => { // This tests the scenario where SmartProxy forwards the real client IP const realClientIP = '203.0.113.1'; const proxyIP = '127.0.0.1'; // Simulate SmartProxy tracking the real client IP securityManager.trackConnectionByIP(realClientIP, 'forwarded-conn1'); securityManager.trackConnectionByIP(realClientIP, 'forwarded-conn2'); securityManager.trackConnectionByIP(realClientIP, 'forwarded-conn3'); // Real client IP should be at limit let result = securityManager.validateIP(realClientIP); expect(result.allowed).toBeFalse(); // But proxy IP should still be allowed result = securityManager.validateIP(proxyIP); expect(result.allowed).toBeTrue(); // Clean up securityManager.removeConnectionByIP(realClientIP, 'forwarded-conn1'); securityManager.removeConnectionByIP(realClientIP, 'forwarded-conn2'); securityManager.removeConnectionByIP(realClientIP, 'forwarded-conn3'); }); tap.test('HttpProxy automatic cleanup', async (tools) => { const testIP = '10.0.0.3'; // Create and immediately remove connections for (let i = 0; i < 5; i++) { securityManager.trackConnectionByIP(testIP, `cleanup-conn${i}`); securityManager.removeConnectionByIP(testIP, `cleanup-conn${i}`); } // Add rate limit entries for (let i = 0; i < 5; i++) { securityManager.validateIP(testIP); } // Wait a bit (cleanup runs every 60 seconds in production) // For testing, we'll just verify the cleanup logic works await tools.delayFor(100); // Manually trigger cleanup (in production this happens automatically) (securityManager as any).performIpCleanup(); // IP should be cleaned up expect(securityManager.getConnectionCountByIP(testIP)).toEqual(0); }); tap.test('Cleanup HttpProxy SecurityManager', async () => { securityManager.clearIPTracking(); }); tap.start();