@push.rocks/smartproxy 19.5.18 → 19.5.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/core/models/index.d.ts +2 -0
- package/dist_ts/core/models/index.js +3 -1
- package/dist_ts/core/models/socket-types.d.ts +14 -0
- package/dist_ts/core/models/socket-types.js +15 -0
- package/dist_ts/core/models/wrapped-socket.d.ts +34 -0
- package/dist_ts/core/models/wrapped-socket.js +82 -0
- package/dist_ts/core/routing/index.d.ts +11 -0
- package/dist_ts/core/routing/index.js +17 -0
- package/dist_ts/core/routing/matchers/domain.d.ts +34 -0
- package/dist_ts/core/routing/matchers/domain.js +91 -0
- package/dist_ts/core/routing/matchers/header.d.ts +32 -0
- package/dist_ts/core/routing/matchers/header.js +94 -0
- package/dist_ts/core/routing/matchers/index.d.ts +18 -0
- package/dist_ts/core/routing/matchers/index.js +20 -0
- package/dist_ts/core/routing/matchers/ip.d.ts +53 -0
- package/dist_ts/core/routing/matchers/ip.js +169 -0
- package/dist_ts/core/routing/matchers/path.d.ts +44 -0
- package/dist_ts/core/routing/matchers/path.js +148 -0
- package/dist_ts/core/routing/route-manager.d.ts +88 -0
- package/dist_ts/core/routing/route-manager.js +342 -0
- package/dist_ts/core/routing/route-utils.d.ts +28 -0
- package/dist_ts/core/routing/route-utils.js +67 -0
- package/dist_ts/core/routing/specificity.d.ts +30 -0
- package/dist_ts/core/routing/specificity.js +115 -0
- package/dist_ts/core/routing/types.d.ts +41 -0
- package/dist_ts/core/routing/types.js +5 -0
- package/dist_ts/core/utils/index.d.ts +0 -2
- package/dist_ts/core/utils/index.js +1 -3
- package/dist_ts/core/utils/route-manager.d.ts +0 -30
- package/dist_ts/core/utils/route-manager.js +6 -47
- package/dist_ts/core/utils/route-utils.d.ts +2 -68
- package/dist_ts/core/utils/route-utils.js +21 -218
- package/dist_ts/core/utils/security-utils.js +4 -4
- package/dist_ts/core/utils/socket-utils.d.ts +0 -15
- package/dist_ts/core/utils/socket-utils.js +1 -35
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +47 -32
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +51 -32
- package/dist_ts/index.d.ts +2 -5
- package/dist_ts/index.js +5 -11
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -1
- package/dist_ts/proxies/http-proxy/http-proxy.js +15 -60
- package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -90
- package/dist_ts/proxies/http-proxy/models/types.js +1 -242
- package/dist_ts/proxies/http-proxy/request-handler.d.ts +3 -5
- package/dist_ts/proxies/http-proxy/request-handler.js +20 -171
- package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +2 -5
- package/dist_ts/proxies/http-proxy/websocket-handler.js +15 -23
- package/dist_ts/proxies/index.d.ts +2 -2
- package/dist_ts/proxies/index.js +4 -3
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +3 -1
- package/dist_ts/proxies/smart-proxy/connection-manager.js +15 -7
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +2 -1
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -2
- package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/index.js +2 -2
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +6 -2
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +48 -25
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +15 -4
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +10 -43
- package/dist_ts/routing/router/http-router.d.ts +89 -0
- package/dist_ts/routing/router/http-router.js +205 -0
- package/dist_ts/routing/router/index.d.ts +2 -5
- package/dist_ts/routing/router/index.js +3 -4
- package/package.json +1 -1
- package/readme.delete.md +187 -0
- package/readme.hints.md +210 -1
- package/readme.plan.md +621 -0
- package/readme.routing.md +341 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/models/index.ts +2 -0
- package/ts/core/models/socket-types.ts +21 -0
- package/ts/core/models/wrapped-socket.ts +99 -0
- package/ts/core/routing/index.ts +21 -0
- package/ts/core/routing/matchers/domain.ts +119 -0
- package/ts/core/routing/matchers/header.ts +120 -0
- package/ts/core/routing/matchers/index.ts +22 -0
- package/ts/core/routing/matchers/ip.ts +207 -0
- package/ts/core/routing/matchers/path.ts +184 -0
- package/ts/core/{utils → routing}/route-manager.ts +7 -57
- package/ts/core/routing/route-utils.ts +88 -0
- package/ts/core/routing/specificity.ts +141 -0
- package/ts/core/routing/types.ts +49 -0
- package/ts/core/utils/index.ts +0 -2
- package/ts/core/utils/security-utils.ts +3 -7
- package/ts/core/utils/socket-utils.ts +0 -44
- package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +47 -33
- package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +55 -35
- package/ts/index.ts +4 -14
- package/ts/proxies/http-proxy/http-proxy.ts +13 -68
- package/ts/proxies/http-proxy/models/types.ts +0 -324
- package/ts/proxies/http-proxy/request-handler.ts +15 -186
- package/ts/proxies/http-proxy/websocket-handler.ts +15 -26
- package/ts/proxies/index.ts +3 -2
- package/ts/proxies/smart-proxy/connection-manager.ts +15 -7
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +6 -2
- package/ts/proxies/smart-proxy/index.ts +1 -1
- package/ts/proxies/smart-proxy/models/interfaces.ts +8 -2
- package/ts/proxies/smart-proxy/route-connection-handler.ts +58 -30
- package/ts/proxies/smart-proxy/smart-proxy.ts +15 -3
- package/ts/proxies/smart-proxy/utils/route-utils.ts +11 -49
- package/ts/routing/router/http-router.ts +266 -0
- package/ts/routing/router/index.ts +3 -8
- package/readme.problems.md +0 -170
- package/ts/core/utils/route-utils.ts +0 -312
- package/ts/proxies/smart-proxy/route-manager.ts +0 -554
- package/ts/routing/router/proxy-router.ts +0 -437
- package/ts/routing/router/route-router.ts +0 -482
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import {
|
|
3
3
|
createLogger,
|
|
4
|
-
RouteManager,
|
|
5
|
-
convertLegacyConfigToRouteConfig
|
|
6
4
|
} from './models/types.js';
|
|
5
|
+
import { SharedRouteManager as RouteManager } from '../../core/routing/route-manager.js';
|
|
7
6
|
import type {
|
|
8
7
|
IHttpProxyOptions,
|
|
9
|
-
ILogger
|
|
10
|
-
IReverseProxyConfig
|
|
8
|
+
ILogger
|
|
11
9
|
} from './models/types.js';
|
|
12
10
|
import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
|
|
13
11
|
import type { IRouteContext, IHttpRouteContext } from '../../core/models/route-context.js';
|
|
@@ -16,8 +14,7 @@ import { CertificateManager } from './certificate-manager.js';
|
|
|
16
14
|
import { ConnectionPool } from './connection-pool.js';
|
|
17
15
|
import { RequestHandler, type IMetricsTracker } from './request-handler.js';
|
|
18
16
|
import { WebSocketHandler } from './websocket-handler.js';
|
|
19
|
-
import {
|
|
20
|
-
import { RouteRouter } from '../../routing/router/route-router.js';
|
|
17
|
+
import { HttpRouter } from '../../routing/router/index.js';
|
|
21
18
|
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
22
19
|
import { FunctionCache } from './function-cache.js';
|
|
23
20
|
|
|
@@ -43,8 +40,7 @@ export class HttpProxy implements IMetricsTracker {
|
|
|
43
40
|
private connectionPool: ConnectionPool;
|
|
44
41
|
private requestHandler: RequestHandler;
|
|
45
42
|
private webSocketHandler: WebSocketHandler;
|
|
46
|
-
private
|
|
47
|
-
private router = new RouteRouter(); // New modern router
|
|
43
|
+
private router = new HttpRouter(); // Unified HTTP router
|
|
48
44
|
private routeManager: RouteManager;
|
|
49
45
|
private functionCache: FunctionCache;
|
|
50
46
|
|
|
@@ -87,7 +83,6 @@ export class HttpProxy implements IMetricsTracker {
|
|
|
87
83
|
// Defaults for SmartProxy integration
|
|
88
84
|
connectionPoolSize: optionsArg.connectionPoolSize || 50,
|
|
89
85
|
portProxyIntegration: optionsArg.portProxyIntegration || false,
|
|
90
|
-
useExternalPort80Handler: optionsArg.useExternalPort80Handler || false,
|
|
91
86
|
// Backend protocol (http1 or http2)
|
|
92
87
|
backendProtocol: optionsArg.backendProtocol || 'http1',
|
|
93
88
|
// Default ACME options
|
|
@@ -107,7 +102,11 @@ export class HttpProxy implements IMetricsTracker {
|
|
|
107
102
|
this.logger = createLogger(this.options.logLevel);
|
|
108
103
|
|
|
109
104
|
// Initialize route manager
|
|
110
|
-
this.routeManager = new RouteManager(
|
|
105
|
+
this.routeManager = new RouteManager({
|
|
106
|
+
logger: this.logger,
|
|
107
|
+
enableDetailedLogging: this.options.logLevel === 'debug',
|
|
108
|
+
routes: []
|
|
109
|
+
});
|
|
111
110
|
|
|
112
111
|
// Initialize function cache
|
|
113
112
|
this.functionCache = new FunctionCache(this.logger, {
|
|
@@ -121,15 +120,13 @@ export class HttpProxy implements IMetricsTracker {
|
|
|
121
120
|
this.requestHandler = new RequestHandler(
|
|
122
121
|
this.options,
|
|
123
122
|
this.connectionPool,
|
|
124
|
-
this.legacyRouter, // Still use legacy router for backward compatibility
|
|
125
123
|
this.routeManager,
|
|
126
124
|
this.functionCache,
|
|
127
|
-
this.router
|
|
125
|
+
this.router
|
|
128
126
|
);
|
|
129
127
|
this.webSocketHandler = new WebSocketHandler(
|
|
130
128
|
this.options,
|
|
131
129
|
this.connectionPool,
|
|
132
|
-
this.legacyRouter,
|
|
133
130
|
this.routes // Pass current routes to WebSocketHandler
|
|
134
131
|
);
|
|
135
132
|
|
|
@@ -429,65 +426,13 @@ export class HttpProxy implements IMetricsTracker {
|
|
|
429
426
|
}
|
|
430
427
|
}
|
|
431
428
|
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const defaultPort = 443; // Default port for HTTPS when using 'preserve'
|
|
436
|
-
// and will be removed in the future
|
|
437
|
-
const legacyConfigs: IReverseProxyConfig[] = [];
|
|
438
|
-
|
|
439
|
-
for (const domain of currentHostnames) {
|
|
440
|
-
// Find route for this domain
|
|
441
|
-
const route = routes.find(r => {
|
|
442
|
-
const domains = Array.isArray(r.match.domains) ? r.match.domains : [r.match.domains];
|
|
443
|
-
return domains.includes(domain);
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
if (!route || route.action.type !== 'forward' || !route.action.target) {
|
|
447
|
-
continue;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Skip routes with function-based targets - we'll handle them during request processing
|
|
451
|
-
if (typeof route.action.target.host === 'function' || typeof route.action.target.port === 'function') {
|
|
452
|
-
this.logger.info(`Domain ${domain} uses function-based targets - will be handled at request time`);
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Extract static target information
|
|
457
|
-
const targetHosts = Array.isArray(route.action.target.host)
|
|
458
|
-
? route.action.target.host
|
|
459
|
-
: [route.action.target.host];
|
|
460
|
-
|
|
461
|
-
// Handle 'preserve' port value
|
|
462
|
-
const targetPort = route.action.target.port === 'preserve' ? defaultPort : route.action.target.port;
|
|
463
|
-
|
|
464
|
-
// Get certificate information
|
|
465
|
-
const certData = certificateUpdates.get(domain);
|
|
466
|
-
const defaultCerts = this.certificateManager.getDefaultCertificates();
|
|
467
|
-
|
|
468
|
-
legacyConfigs.push({
|
|
469
|
-
hostName: domain,
|
|
470
|
-
destinationIps: targetHosts,
|
|
471
|
-
destinationPorts: [targetPort],
|
|
472
|
-
privateKey: certData?.key || defaultCerts.key,
|
|
473
|
-
publicKey: certData?.cert || defaultCerts.cert
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Update the router with legacy configs
|
|
478
|
-
// Handle both old and new router interfaces
|
|
479
|
-
if (typeof this.router.setRoutes === 'function') {
|
|
480
|
-
this.router.setRoutes(routes);
|
|
481
|
-
} else if (typeof this.router.setNewProxyConfigs === 'function') {
|
|
482
|
-
this.router.setNewProxyConfigs(legacyConfigs);
|
|
483
|
-
} else {
|
|
484
|
-
this.logger.warn('Router has no recognized configuration method');
|
|
485
|
-
}
|
|
429
|
+
// Update the router with new routes
|
|
430
|
+
this.router.setRoutes(routes);
|
|
486
431
|
|
|
487
432
|
// Update WebSocket handler with new routes
|
|
488
433
|
this.webSocketHandler.setRoutes(routes);
|
|
489
434
|
|
|
490
|
-
this.logger.info(`Route configuration updated with ${routes.length} routes
|
|
435
|
+
this.logger.info(`Route configuration updated with ${routes.length} routes`);
|
|
491
436
|
}
|
|
492
437
|
|
|
493
438
|
// Legacy methods have been removed.
|
|
@@ -13,7 +13,6 @@ export interface IAcmeOptions {
|
|
|
13
13
|
skipConfiguredCerts?: boolean;
|
|
14
14
|
}
|
|
15
15
|
import type { IRouteConfig } from '../../smart-proxy/models/route-types.js';
|
|
16
|
-
import type { IRouteContext } from '../../../core/models/route-context.js';
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* Configuration options for HttpProxy
|
|
@@ -34,7 +33,6 @@ export interface IHttpProxyOptions {
|
|
|
34
33
|
// Settings for SmartProxy integration
|
|
35
34
|
connectionPoolSize?: number; // Maximum connections to maintain in the pool to each backend
|
|
36
35
|
portProxyIntegration?: boolean; // Flag to indicate this proxy is used by SmartProxy
|
|
37
|
-
useExternalPort80Handler?: boolean; // @deprecated - use SmartCertManager instead
|
|
38
36
|
// Protocol to use when proxying to backends: HTTP/1.x or HTTP/2
|
|
39
37
|
backendProtocol?: 'http1' | 'http2';
|
|
40
38
|
|
|
@@ -58,329 +56,7 @@ export interface ICertificateEntry {
|
|
|
58
56
|
expires?: Date;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
/**
|
|
62
|
-
* @deprecated Use IRouteConfig instead. This interface will be removed in a future release.
|
|
63
|
-
*
|
|
64
|
-
* IMPORTANT: This is a legacy interface maintained only for backward compatibility.
|
|
65
|
-
* New code should use IRouteConfig for all configuration purposes.
|
|
66
|
-
*
|
|
67
|
-
* @see IRouteConfig for the modern, recommended configuration format
|
|
68
|
-
*/
|
|
69
|
-
export interface IReverseProxyConfig {
|
|
70
|
-
/** Target hostnames/IPs to proxy requests to */
|
|
71
|
-
destinationIps: string[];
|
|
72
|
-
|
|
73
|
-
/** Target ports to proxy requests to */
|
|
74
|
-
destinationPorts: number[];
|
|
75
|
-
|
|
76
|
-
/** Hostname to match for routing */
|
|
77
|
-
hostName: string;
|
|
78
|
-
|
|
79
|
-
/** SSL private key for this host (PEM format) */
|
|
80
|
-
privateKey: string;
|
|
81
|
-
|
|
82
|
-
/** SSL public key/certificate for this host (PEM format) */
|
|
83
|
-
publicKey: string;
|
|
84
|
-
|
|
85
|
-
/** Basic authentication configuration */
|
|
86
|
-
authentication?: {
|
|
87
|
-
type: 'Basic';
|
|
88
|
-
user: string;
|
|
89
|
-
pass: string;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
/** Whether to rewrite the Host header to match the target */
|
|
93
|
-
rewriteHostHeader?: boolean;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Protocol to use when proxying to this backend: 'http1' or 'http2'.
|
|
97
|
-
* Overrides the global backendProtocol option if set.
|
|
98
|
-
*/
|
|
99
|
-
backendProtocol?: 'http1' | 'http2';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Convert a legacy IReverseProxyConfig to the modern IRouteConfig format
|
|
104
|
-
*
|
|
105
|
-
* @deprecated This function is maintained for backward compatibility.
|
|
106
|
-
* New code should create IRouteConfig objects directly.
|
|
107
|
-
*
|
|
108
|
-
* @param legacyConfig The legacy configuration to convert
|
|
109
|
-
* @param proxyPort The port the proxy listens on
|
|
110
|
-
* @returns A modern route configuration equivalent to the legacy config
|
|
111
|
-
*/
|
|
112
|
-
export function convertLegacyConfigToRouteConfig(
|
|
113
|
-
legacyConfig: IReverseProxyConfig,
|
|
114
|
-
proxyPort: number
|
|
115
|
-
): IRouteConfig {
|
|
116
|
-
// Create basic route configuration
|
|
117
|
-
const routeConfig: IRouteConfig = {
|
|
118
|
-
// Match properties
|
|
119
|
-
match: {
|
|
120
|
-
ports: proxyPort,
|
|
121
|
-
domains: legacyConfig.hostName
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
// Action properties
|
|
125
|
-
action: {
|
|
126
|
-
type: 'forward',
|
|
127
|
-
target: {
|
|
128
|
-
host: legacyConfig.destinationIps,
|
|
129
|
-
port: legacyConfig.destinationPorts[0]
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
// TLS mode is always 'terminate' for legacy configs
|
|
133
|
-
tls: {
|
|
134
|
-
mode: 'terminate',
|
|
135
|
-
certificate: {
|
|
136
|
-
key: legacyConfig.privateKey,
|
|
137
|
-
cert: legacyConfig.publicKey
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
// Advanced options
|
|
142
|
-
advanced: {
|
|
143
|
-
// Rewrite host header if specified
|
|
144
|
-
headers: legacyConfig.rewriteHostHeader ? { 'host': '{domain}' } : {}
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
// Metadata
|
|
149
|
-
name: `Legacy Config - ${legacyConfig.hostName}`,
|
|
150
|
-
priority: 0, // Default priority
|
|
151
|
-
enabled: true
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// Add authentication if present
|
|
155
|
-
if (legacyConfig.authentication) {
|
|
156
|
-
routeConfig.security = {
|
|
157
|
-
authentication: {
|
|
158
|
-
type: 'basic',
|
|
159
|
-
credentials: [{
|
|
160
|
-
username: legacyConfig.authentication.user,
|
|
161
|
-
password: legacyConfig.authentication.pass
|
|
162
|
-
}]
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Add backend protocol if specified
|
|
168
|
-
if (legacyConfig.backendProtocol) {
|
|
169
|
-
if (!routeConfig.action.options) {
|
|
170
|
-
routeConfig.action.options = {};
|
|
171
|
-
}
|
|
172
|
-
routeConfig.action.options.backendProtocol = legacyConfig.backendProtocol;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return routeConfig;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Route manager for NetworkProxy
|
|
180
|
-
* Handles route matching and configuration
|
|
181
|
-
*/
|
|
182
|
-
export class RouteManager {
|
|
183
|
-
private routes: IRouteConfig[] = [];
|
|
184
|
-
private logger: ILogger;
|
|
185
|
-
|
|
186
|
-
constructor(logger: ILogger) {
|
|
187
|
-
this.logger = logger;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Update the routes configuration
|
|
192
|
-
*/
|
|
193
|
-
public updateRoutes(routes: IRouteConfig[]): void {
|
|
194
|
-
// Sort routes by priority (higher first)
|
|
195
|
-
this.routes = [...routes].sort((a, b) => {
|
|
196
|
-
const priorityA = a.priority ?? 0;
|
|
197
|
-
const priorityB = b.priority ?? 0;
|
|
198
|
-
return priorityB - priorityA;
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
this.logger.info(`Updated RouteManager with ${this.routes.length} routes`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Get all routes
|
|
206
|
-
*/
|
|
207
|
-
public getRoutes(): IRouteConfig[] {
|
|
208
|
-
return [...this.routes];
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Find the first matching route for a context
|
|
213
|
-
*/
|
|
214
|
-
public findMatchingRoute(context: IRouteContext): IRouteConfig | null {
|
|
215
|
-
for (const route of this.routes) {
|
|
216
|
-
if (this.matchesRoute(route, context)) {
|
|
217
|
-
return route;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return null;
|
|
221
|
-
}
|
|
222
59
|
|
|
223
|
-
/**
|
|
224
|
-
* Check if a route matches the given context
|
|
225
|
-
*/
|
|
226
|
-
private matchesRoute(route: IRouteConfig, context: IRouteContext): boolean {
|
|
227
|
-
// Skip disabled routes
|
|
228
|
-
if (route.enabled === false) {
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Check domain match if specified
|
|
233
|
-
if (route.match.domains && context.domain) {
|
|
234
|
-
const domains = Array.isArray(route.match.domains)
|
|
235
|
-
? route.match.domains
|
|
236
|
-
: [route.match.domains];
|
|
237
|
-
|
|
238
|
-
if (!domains.some(domainPattern => this.matchDomain(domainPattern, context.domain!))) {
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Check path match if specified
|
|
244
|
-
if (route.match.path && context.path) {
|
|
245
|
-
if (!this.matchPath(route.match.path, context.path)) {
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Check client IP match if specified
|
|
251
|
-
if (route.match.clientIp && context.clientIp) {
|
|
252
|
-
if (!route.match.clientIp.some(ip => this.matchIp(ip, context.clientIp))) {
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Check TLS version match if specified
|
|
258
|
-
if (route.match.tlsVersion && context.tlsVersion) {
|
|
259
|
-
if (!route.match.tlsVersion.includes(context.tlsVersion)) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// All criteria matched
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Match a domain pattern against a domain
|
|
270
|
-
*/
|
|
271
|
-
private matchDomain(pattern: string, domain: string): boolean {
|
|
272
|
-
if (pattern === domain) {
|
|
273
|
-
return true;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (pattern.includes('*')) {
|
|
277
|
-
const regexPattern = pattern
|
|
278
|
-
.replace(/\./g, '\\.')
|
|
279
|
-
.replace(/\*/g, '.*');
|
|
280
|
-
|
|
281
|
-
const regex = new RegExp(`^${regexPattern}$`, 'i');
|
|
282
|
-
return regex.test(domain);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Match a path pattern against a path
|
|
290
|
-
*/
|
|
291
|
-
private matchPath(pattern: string, path: string): boolean {
|
|
292
|
-
if (pattern === path) {
|
|
293
|
-
return true;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (pattern.endsWith('*')) {
|
|
297
|
-
const prefix = pattern.slice(0, -1);
|
|
298
|
-
return path.startsWith(prefix);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return false;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Match an IP pattern against an IP
|
|
306
|
-
* Supports exact matches, wildcard patterns, and CIDR notation
|
|
307
|
-
*/
|
|
308
|
-
private matchIp(pattern: string, ip: string): boolean {
|
|
309
|
-
// Exact match
|
|
310
|
-
if (pattern === ip) {
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Wildcard matching (e.g., 192.168.0.*)
|
|
315
|
-
if (pattern.includes('*')) {
|
|
316
|
-
const regexPattern = pattern
|
|
317
|
-
.replace(/\./g, '\\.')
|
|
318
|
-
.replace(/\*/g, '.*');
|
|
319
|
-
|
|
320
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
321
|
-
return regex.test(ip);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// CIDR matching (e.g., 192.168.0.0/24)
|
|
325
|
-
if (pattern.includes('/')) {
|
|
326
|
-
try {
|
|
327
|
-
const [subnet, bits] = pattern.split('/');
|
|
328
|
-
|
|
329
|
-
// Convert IP addresses to numeric format for comparison
|
|
330
|
-
const ipBinary = this.ipToBinary(ip);
|
|
331
|
-
const subnetBinary = this.ipToBinary(subnet);
|
|
332
|
-
|
|
333
|
-
if (!ipBinary || !subnetBinary) {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Get the subnet mask from CIDR notation
|
|
338
|
-
const mask = parseInt(bits, 10);
|
|
339
|
-
if (isNaN(mask) || mask < 0 || mask > 32) {
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Check if the first 'mask' bits match between IP and subnet
|
|
344
|
-
return ipBinary.slice(0, mask) === subnetBinary.slice(0, mask);
|
|
345
|
-
} catch (error) {
|
|
346
|
-
// If we encounter any error during CIDR matching, return false
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Convert an IP address to its binary representation
|
|
356
|
-
* @param ip The IP address to convert
|
|
357
|
-
* @returns Binary string representation or null if invalid
|
|
358
|
-
*/
|
|
359
|
-
private ipToBinary(ip: string): string | null {
|
|
360
|
-
// Handle IPv4 addresses only for now
|
|
361
|
-
const parts = ip.split('.');
|
|
362
|
-
|
|
363
|
-
// Validate IP format
|
|
364
|
-
if (parts.length !== 4) {
|
|
365
|
-
return null;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Convert each octet to 8-bit binary and concatenate
|
|
369
|
-
try {
|
|
370
|
-
return parts
|
|
371
|
-
.map(part => {
|
|
372
|
-
const num = parseInt(part, 10);
|
|
373
|
-
if (isNaN(num) || num < 0 || num > 255) {
|
|
374
|
-
throw new Error('Invalid IP octet');
|
|
375
|
-
}
|
|
376
|
-
return num.toString(2).padStart(8, '0');
|
|
377
|
-
})
|
|
378
|
-
.join('');
|
|
379
|
-
} catch (error) {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
60
|
|
|
385
61
|
/**
|
|
386
62
|
* Interface for connection tracking in the pool
|