2025-05-15 09:34:01 +00:00
# SmartProxy Interface Consolidation Plan
2025-05-14 12:26:43 +00:00
2025-05-15 08:56:27 +00:00
## Overview
2025-05-14 12:26:43 +00:00
2025-05-15 09:34:01 +00:00
This document outlines a plan to consolidate duplicate and inconsistent interfaces in the SmartProxy codebase, specifically the `IRouteSecurity` interface which is defined twice with different properties. This inconsistency caused issues with security checks for port forwarding. The goal is to unify these interfaces, use consistent property naming, and improve code maintainability.
2025-05-15 09:56:32 +00:00
## Problem Description (RESOLVED)
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
We had two separate `IRouteSecurity` interfaces defined in `ts/proxies/smart-proxy/models/route-types.ts` which have now been consolidated into a single interface:
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
1. **First definition** (previous lines 116-122) - Used in IRouteAction:
2025-05-15 09:34:01 +00:00
```typescript
export interface IRouteSecurity {
allowedIps?: string[];
blockedIps?: string[];
maxConnections?: number;
authentication?: IRouteAuthentication;
}
```
2025-05-15 09:56:32 +00:00
2. **Second definition** (previous lines 253-272) - Used directly in IRouteConfig:
2025-05-15 09:34:01 +00:00
```typescript
export interface IRouteSecurity {
rateLimit?: IRouteRateLimit;
basicAuth?: {...};
jwtAuth?: {...};
ipAllowList?: string[];
ipBlockList?: string[];
}
```
2025-05-15 09:56:32 +00:00
This duplication with inconsistent naming (`allowedIps` vs `ipAllowList` and `blockedIps` vs `ipBlockList` ) caused routing issues when IP security checks were used, particularly with port range configurations.
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
## Implementation Plan (COMPLETED)
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
### Phase 1: Interface Consolidation ✅
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
1. **Create a unified interface definition:** ✅
- Created one comprehensive `IRouteSecurity` interface that includes all properties
- Standardized on `ipAllowList` and `ipBlockList` property names
- Added proper documentation for each property
- Removed the duplicate interface definition
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
2. **Update references to use the unified interface:** ✅
- Updated all code that references the old interface properties
- Updated all configurations to use the new property names
- Ensured implementation in `route-manager.ts` uses the correct property names
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
### Phase 2: Code and Documentation Updates ✅
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
1. **Update type usages and documentation:** ✅
- Updated all code that creates or uses security configurations
- Updated documentation to reflect the new interface structure
- Added examples of the correct property usage
- Documented the changes in this plan
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
2. **Fix TypeScript errors:** ✅
- Fixed TypeScript errors in http-request-handler.ts
- Successfully built the project with `pnpm run build`
2025-05-15 09:34:01 +00:00
2025-05-15 09:56:32 +00:00
## Implementation Completed ✅
2025-05-14 12:26:43 +00:00
2025-05-15 09:56:32 +00:00
The interface consolidation has been successfully implemented with the following changes:
1. **Unified interface created:**
2025-05-15 09:34:01 +00:00
```typescript
2025-05-15 09:56:32 +00:00
// Consolidated interface definition
2025-05-15 09:34:01 +00:00
export interface IRouteSecurity {
// Access control lists
ipAllowList?: string[]; // IP addresses that are allowed to connect
ipBlockList?: string[]; // IP addresses that are blocked from connecting
// Connection limits
maxConnections?: number; // Maximum concurrent connections
// Authentication
authentication?: IRouteAuthentication;
// Rate limiting
rateLimit?: IRouteRateLimit;
// Authentication methods
basicAuth?: {
enabled: boolean;
users: Array< { username: string; password: string }>;
realm?: string;
excludePaths?: string[];
};
jwtAuth?: {
enabled: boolean;
secret: string;
algorithm?: string;
issuer?: string;
audience?: string;
expiresIn?: number;
excludePaths?: string[];
};
}
2025-05-15 08:56:27 +00:00
```
2025-05-15 09:56:32 +00:00
2. **Updated isClientIpAllowed method:**
2025-05-15 08:56:27 +00:00
```typescript
2025-05-15 09:34:01 +00:00
private isClientIpAllowed(route: IRouteConfig, clientIp: string): boolean {
const security = route.action.security;
if (!security) {
return true; // No security settings means allowed
}
// Check blocked IPs first
if (security.ipBlockList & & security.ipBlockList.length > 0) {
for (const pattern of security.ipBlockList) {
if (this.matchIpPattern(pattern, clientIp)) {
return false; // IP is blocked
}
}
}
// If there are allowed IPs, check them
if (security.ipAllowList & & security.ipAllowList.length > 0) {
for (const pattern of security.ipAllowList) {
if (this.matchIpPattern(pattern, clientIp)) {
return true; // IP is allowed
}
}
return false; // IP not in allowed list
}
// No allowed IPs specified, so IP is allowed
return true;
}
2025-05-15 08:56:27 +00:00
```
2025-05-14 12:26:43 +00:00
2025-05-15 09:56:32 +00:00
3. **Fixed port preservation logic:**
```typescript
// In base-handler.ts
protected resolvePort(
port: number | 'preserve' | ((ctx: any) => number),
incomingPort: number = 80
): number {
if (typeof port === 'function') {
try {
// Create a minimal context for the function that includes the incoming port
const ctx = { port: incomingPort };
return port(ctx);
} catch (err) {
console.error('Error resolving port function:', err);
return incomingPort; // Fall back to incoming port
}
} else if (port === 'preserve') {
return incomingPort; // Use the actual incoming port for 'preserve'
} else {
return port;
}
}
```
4. **Fixed TypeScript error in http-request-handler.ts:**
```typescript
// Safely check for host property existence
if (options.headers & & 'host' in options.headers) {
// Only apply if host header rewrite is enabled or not explicitly disabled
const shouldRewriteHost = route?.action.options?.rewriteHostHeader !== false;
if (shouldRewriteHost) {
// Safely cast to OutgoingHttpHeaders to access host property
(options.headers as plugins.http.OutgoingHttpHeaders).host = `${destination.host}:${destination.port}` ;
}
}
```
## Achieved Benefits ✅
2025-05-14 12:26:43 +00:00
2025-05-15 09:34:01 +00:00
- **Improved Consistency**: Single, unified interface with consistent property naming
2025-05-15 09:56:32 +00:00
- **Better Type Safety**: Eliminated confusing duplicate interface definitions
- **Reduced Errors**: Prevented misunderstandings about which property names to use
2025-05-15 09:34:01 +00:00
- **Forward Compatibility**: Clearer path for future security enhancements
- **Better Developer Experience**: Simplified interface with comprehensive documentation
2025-05-15 09:56:32 +00:00
- **Fixed Issues**: Port preservation with port ranges now works correctly with security checks
2025-05-14 12:26:43 +00:00
2025-05-15 09:56:32 +00:00
## Verification ✅
2025-05-14 12:26:43 +00:00
2025-05-15 09:56:32 +00:00
- The project builds successfully with `pnpm run build`
- The unified interface works properly with all type checking
- The port range forwarding with `port: 'preserve'` now works correctly with IP security rules
- The security checks consistently use the standardized property names throughout the codebase