120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
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(); |