@push.rocks/smartproxy 19.5.2 → 19.5.4
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 +1 -1
- package/dist_ts/proxies/http-proxy/models/types.js +2 -2
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +2 -5
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +0 -1
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/nftables-manager.js +5 -6
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -2
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +84 -5
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +2 -0
- package/dist_ts/proxies/smart-proxy/route-manager.js +7 -8
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +10 -9
- package/package.json +2 -2
- package/readme.hints.md +131 -5
- package/readme.md +515 -301
- package/readme.problems.md +86 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/proxies/http-proxy/models/types.ts +1 -1
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +1 -4
- package/ts/proxies/smart-proxy/models/route-types.ts +0 -3
- package/ts/proxies/smart-proxy/nftables-manager.ts +4 -5
- package/ts/proxies/smart-proxy/route-connection-handler.ts +97 -4
- package/ts/proxies/smart-proxy/route-manager.ts +7 -8
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +11 -9
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# SmartProxy Module Problems
|
|
2
|
+
|
|
3
|
+
Based on test analysis, the following potential issues have been identified in the SmartProxy module:
|
|
4
|
+
|
|
5
|
+
## 1. HttpProxy Route Configuration Issue
|
|
6
|
+
**Location**: `ts/proxies/http-proxy/http-proxy.ts:380`
|
|
7
|
+
**Problem**: The HttpProxy is trying to read the 'type' property of an undefined object when updating route configurations.
|
|
8
|
+
**Evidence**: `test.http-forwarding-fix.ts` fails with:
|
|
9
|
+
```
|
|
10
|
+
TypeError: Cannot read properties of undefined (reading 'type')
|
|
11
|
+
at HttpProxy.updateRouteConfigs (/mnt/data/lossless/push.rocks/smartproxy/ts/proxies/http-proxy/http-proxy.ts:380:24)
|
|
12
|
+
```
|
|
13
|
+
**Impact**: Routes with `useHttpProxy` configuration may not work properly.
|
|
14
|
+
|
|
15
|
+
## 2. Connection Forwarding Issues
|
|
16
|
+
**Problem**: Basic TCP forwarding appears to not be working correctly after the simplification to just 'forward' and 'socket-handler' action types.
|
|
17
|
+
**Evidence**: Multiple forwarding tests timeout waiting for data to be forwarded:
|
|
18
|
+
- `test.forwarding-fix-verification.ts` - times out waiting for forwarded data
|
|
19
|
+
- `test.connection-forwarding.ts` - times out on SNI-based forwarding
|
|
20
|
+
**Impact**: The 'forward' action type may not be properly forwarding connections to target servers.
|
|
21
|
+
|
|
22
|
+
## 3. Missing Certificate Manager Methods
|
|
23
|
+
**Problem**: Tests expect `provisionAllCertificates` method on certificate manager but it may not exist or may not be properly initialized.
|
|
24
|
+
**Evidence**: Multiple tests fail with "this.certManager.provisionAllCertificates is not a function"
|
|
25
|
+
**Impact**: Certificate provisioning may not work as expected.
|
|
26
|
+
|
|
27
|
+
## 4. Route Update Mechanism
|
|
28
|
+
**Problem**: The route update mechanism may have issues preserving certificate manager callbacks and other state.
|
|
29
|
+
**Evidence**: Tests specifically designed to verify callback preservation after route updates.
|
|
30
|
+
**Impact**: Dynamic route updates might break certificate management functionality.
|
|
31
|
+
|
|
32
|
+
## 5. Route-Specific Security Not Fully Implemented
|
|
33
|
+
**Problem**: While the route definitions support security configurations (ipAllowList, ipBlockList, authentication), these are not being enforced at the route level.
|
|
34
|
+
**Evidence**:
|
|
35
|
+
- SecurityManager has methods like `isIPAuthorized` for route-specific security
|
|
36
|
+
- Route connection handler only checks global IP validation, not route-specific security rules
|
|
37
|
+
- No evidence of route.action.security being checked when handling connections
|
|
38
|
+
**Impact**: Route-specific security rules defined in configuration are not enforced, potentially allowing unauthorized access.
|
|
39
|
+
**Status**: ✅ FIXED - Route-specific IP allow/block lists are now enforced when a route is matched. Authentication is logged as not enforceable for non-terminated connections.
|
|
40
|
+
**Additional Fix**: Removed security checks from route matching logic - security is now properly enforced AFTER a route is matched, not during matching.
|
|
41
|
+
|
|
42
|
+
## 6. Security Property Location Consolidation
|
|
43
|
+
**Problem**: Security was defined in two places - route.security and route.action.security - causing confusion.
|
|
44
|
+
**Status**: ✅ FIXED - Consolidated to only route.security. Removed action.security from types and updated all references.
|
|
45
|
+
|
|
46
|
+
## Recommendations
|
|
47
|
+
|
|
48
|
+
1. **Verify Forward Action Implementation**: Check that the 'forward' action type properly establishes bidirectional data flow between client and target server. ✅ FIXED - Basic forwarding now works correctly.
|
|
49
|
+
|
|
50
|
+
2. **Fix HttpProxy Route Handling**: Ensure that route objects passed to HttpProxy.updateRouteConfigs have the expected structure with all required properties. ✅ FIXED - Routes now preserve their structure.
|
|
51
|
+
|
|
52
|
+
3. **Review Certificate Manager API**: Ensure all expected methods exist and are properly documented.
|
|
53
|
+
|
|
54
|
+
4. **Add Integration Tests**: Many unit tests are testing internal implementation details. Consider adding more integration tests that test the public API.
|
|
55
|
+
|
|
56
|
+
5. **Implement Route-Specific Security**: Add security checks when a route is matched to enforce route-specific IP allow/block lists and authentication rules. ✅ FIXED - IP allow/block lists are now enforced at the route level.
|
|
57
|
+
|
|
58
|
+
6. **Fix TLS Detection Logic**: The connection handler was treating all connections as TLS. This has been partially fixed but needs proper testing for all TLS modes.
|
|
59
|
+
|
|
60
|
+
## 7. HTTP Domain Matching Issue
|
|
61
|
+
**Problem**: Routes with domain restrictions fail to match HTTP connections because domain information is only available after HTTP headers are received, but route matching happens immediately upon connection.
|
|
62
|
+
**Evidence**:
|
|
63
|
+
- `test.http-port8080-forwarding.ts` - "No route found for connection on port 8080" despite having a matching route
|
|
64
|
+
- HTTP connections provide domain info via the Host header, which arrives after the initial TCP connection
|
|
65
|
+
- Route matching in `handleInitialData` happens before HTTP headers are parsed
|
|
66
|
+
**Impact**: HTTP routes with domain restrictions cannot be matched, forcing users to remove domain restrictions for HTTP routes.
|
|
67
|
+
**Root Cause**: For non-TLS connections, SmartProxy attempts to match routes immediately, but the domain information needed for matching is only available after parsing HTTP headers.
|
|
68
|
+
**Status**: ✅ FIXED - Added skipDomainCheck parameter to route matching for HTTP proxy ports. When a port is configured with useHttpProxy and the connection is not TLS, domain validation is skipped at the initial route matching stage, allowing the HttpProxy to handle domain-based routing after headers are received.
|
|
69
|
+
|
|
70
|
+
## 8. HttpProxy Plain HTTP Forwarding Issue
|
|
71
|
+
**Problem**: HttpProxy is an HTTPS server but SmartProxy forwards plain HTTP connections to it via `useHttpProxy` configuration.
|
|
72
|
+
**Evidence**:
|
|
73
|
+
- `test.http-port8080-forwarding.ts` - Connection immediately closed after forwarding to HttpProxy
|
|
74
|
+
- HttpProxy is created with `http2.createSecureServer` expecting TLS connections
|
|
75
|
+
- SmartProxy forwards raw HTTP data to HttpProxy's HTTPS port
|
|
76
|
+
**Impact**: Plain HTTP connections cannot be handled by HttpProxy, despite `useHttpProxy` configuration suggesting this should work.
|
|
77
|
+
**Root Cause**: Design mismatch - HttpProxy is designed for HTTPS/TLS termination, not plain HTTP forwarding.
|
|
78
|
+
**Status**: Documented. The `useHttpProxy` configuration should only be used for ports that receive TLS connections requiring termination. For plain HTTP forwarding, use direct forwarding without HttpProxy.
|
|
79
|
+
|
|
80
|
+
## 9. Route Security Configuration Location Issue
|
|
81
|
+
**Problem**: Tests were placing security configuration in `route.action.security` instead of `route.security`.
|
|
82
|
+
**Evidence**:
|
|
83
|
+
- `test.route-security.ts` - IP block list test failing because security was in wrong location
|
|
84
|
+
- IRouteConfig interface defines security at route level, not inside action
|
|
85
|
+
**Impact**: Security rules defined in action.security were ignored, causing tests to fail.
|
|
86
|
+
**Status**: ✅ FIXED - Updated tests to place security configuration at the correct location (route.security).
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '19.5.
|
|
6
|
+
version: '19.5.3',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
}
|
|
@@ -153,7 +153,7 @@ export function convertLegacyConfigToRouteConfig(
|
|
|
153
153
|
|
|
154
154
|
// Add authentication if present
|
|
155
155
|
if (legacyConfig.authentication) {
|
|
156
|
-
routeConfig.
|
|
156
|
+
routeConfig.security = {
|
|
157
157
|
authentication: {
|
|
158
158
|
type: 'basic',
|
|
159
159
|
credentials: [{
|
|
@@ -73,10 +73,7 @@ export class HttpProxyBridge {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
return {
|
|
76
|
-
|
|
77
|
-
target: route.action.target,
|
|
78
|
-
tls: route.action.tls,
|
|
79
|
-
security: route.action.security,
|
|
76
|
+
...route, // Keep the original route structure
|
|
80
77
|
match: {
|
|
81
78
|
...route.match,
|
|
82
79
|
domains: domain // Ensure domains is always set for HttpProxy
|
|
@@ -175,13 +175,12 @@ export class NFTablesManager {
|
|
|
175
175
|
};
|
|
176
176
|
|
|
177
177
|
// Add security-related options
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
options.ipAllowList = security.ipAllowList;
|
|
178
|
+
if (route.security?.ipAllowList?.length) {
|
|
179
|
+
options.ipAllowList = route.security.ipAllowList;
|
|
181
180
|
}
|
|
182
181
|
|
|
183
|
-
if (security?.ipBlockList?.length) {
|
|
184
|
-
options.ipBlockList = security.ipBlockList;
|
|
182
|
+
if (route.security?.ipBlockList?.length) {
|
|
183
|
+
options.ipBlockList = route.security.ipBlockList;
|
|
185
184
|
}
|
|
186
185
|
|
|
187
186
|
// Add QoS options
|
|
@@ -146,18 +146,42 @@ export class RouteConnectionHandler {
|
|
|
146
146
|
);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
//
|
|
150
|
-
this.
|
|
149
|
+
// Handle the connection - wait for initial data to determine if it's TLS
|
|
150
|
+
this.handleInitialData(socket, record);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
* Handle
|
|
154
|
+
* Handle initial data from a connection to determine routing
|
|
155
155
|
*/
|
|
156
|
-
private
|
|
156
|
+
private handleInitialData(socket: plugins.net.Socket, record: IConnectionRecord): void {
|
|
157
157
|
const connectionId = record.id;
|
|
158
158
|
const localPort = record.localPort;
|
|
159
159
|
let initialDataReceived = false;
|
|
160
160
|
|
|
161
|
+
// Check if any routes on this port require TLS handling
|
|
162
|
+
const allRoutes = this.routeManager.getAllRoutes();
|
|
163
|
+
const needsTlsHandling = allRoutes.some(route => {
|
|
164
|
+
// Check if route matches this port
|
|
165
|
+
const matchesPort = this.routeManager.getRoutesForPort(localPort).includes(route);
|
|
166
|
+
|
|
167
|
+
return matchesPort &&
|
|
168
|
+
route.action.type === 'forward' &&
|
|
169
|
+
route.action.tls &&
|
|
170
|
+
(route.action.tls.mode === 'terminate' ||
|
|
171
|
+
route.action.tls.mode === 'passthrough');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// If no routes require TLS handling and it's not port 443, route immediately
|
|
175
|
+
if (!needsTlsHandling && localPort !== 443) {
|
|
176
|
+
// Set up error handler
|
|
177
|
+
socket.on('error', this.connectionManager.handleError('incoming', record));
|
|
178
|
+
|
|
179
|
+
// Route immediately for non-TLS connections
|
|
180
|
+
this.routeConnection(socket, record, '', undefined);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Otherwise, wait for initial data to check if it's TLS
|
|
161
185
|
// Set an initial timeout for handshake data
|
|
162
186
|
let initialTimeout: NodeJS.Timeout | null = setTimeout(() => {
|
|
163
187
|
if (!initialDataReceived) {
|
|
@@ -296,6 +320,12 @@ export class RouteConnectionHandler {
|
|
|
296
320
|
const localPort = record.localPort;
|
|
297
321
|
const remoteIP = record.remoteIP;
|
|
298
322
|
|
|
323
|
+
// Check if this is an HTTP proxy port
|
|
324
|
+
const isHttpProxyPort = this.settings.useHttpProxy?.includes(localPort);
|
|
325
|
+
|
|
326
|
+
// For HTTP proxy ports without TLS, skip domain check since domain info comes from HTTP headers
|
|
327
|
+
const skipDomainCheck = isHttpProxyPort && !record.isTLS;
|
|
328
|
+
|
|
299
329
|
// Find matching route
|
|
300
330
|
const routeMatch = this.routeManager.findMatchingRoute({
|
|
301
331
|
port: localPort,
|
|
@@ -303,6 +333,7 @@ export class RouteConnectionHandler {
|
|
|
303
333
|
clientIp: remoteIP,
|
|
304
334
|
path: undefined, // We don't have path info at this point
|
|
305
335
|
tlsVersion: undefined, // We don't extract TLS version yet
|
|
336
|
+
skipDomainCheck: skipDomainCheck,
|
|
306
337
|
});
|
|
307
338
|
|
|
308
339
|
if (!routeMatch) {
|
|
@@ -382,6 +413,56 @@ export class RouteConnectionHandler {
|
|
|
382
413
|
});
|
|
383
414
|
}
|
|
384
415
|
|
|
416
|
+
// Apply route-specific security checks
|
|
417
|
+
if (route.security) {
|
|
418
|
+
// Check IP allow/block lists
|
|
419
|
+
if (route.security.ipAllowList || route.security.ipBlockList) {
|
|
420
|
+
const isIPAllowed = this.securityManager.isIPAuthorized(
|
|
421
|
+
remoteIP,
|
|
422
|
+
route.security.ipAllowList || [],
|
|
423
|
+
route.security.ipBlockList || []
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
if (!isIPAllowed) {
|
|
427
|
+
logger.log('warn', `IP ${remoteIP} blocked by route security for route ${route.name || 'unnamed'} (connection: ${connectionId})`, {
|
|
428
|
+
connectionId,
|
|
429
|
+
remoteIP,
|
|
430
|
+
routeName: route.name || 'unnamed',
|
|
431
|
+
component: 'route-handler'
|
|
432
|
+
});
|
|
433
|
+
socket.end();
|
|
434
|
+
this.connectionManager.cleanupConnection(record, 'route_ip_blocked');
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Check max connections per route
|
|
440
|
+
if (route.security.maxConnections !== undefined) {
|
|
441
|
+
// TODO: Implement per-route connection tracking
|
|
442
|
+
// For now, log that this feature is not yet implemented
|
|
443
|
+
if (this.settings.enableDetailedLogging) {
|
|
444
|
+
logger.log('warn', `Route ${route.name} has maxConnections=${route.security.maxConnections} configured but per-route connection limits are not yet implemented`, {
|
|
445
|
+
connectionId,
|
|
446
|
+
routeName: route.name,
|
|
447
|
+
component: 'route-handler'
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Check authentication requirements
|
|
453
|
+
if (route.security.authentication || route.security.basicAuth || route.security.jwtAuth) {
|
|
454
|
+
// Authentication checks would typically happen at the HTTP layer
|
|
455
|
+
// For non-HTTP connections or passthrough, we can't enforce authentication
|
|
456
|
+
if (route.action.type === 'forward' && route.action.tls?.mode !== 'terminate') {
|
|
457
|
+
logger.log('warn', `Route ${route.name} has authentication configured but it cannot be enforced for non-terminated connections`, {
|
|
458
|
+
connectionId,
|
|
459
|
+
routeName: route.name,
|
|
460
|
+
tlsMode: route.action.tls?.mode || 'none',
|
|
461
|
+
component: 'route-handler'
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
385
466
|
|
|
386
467
|
// Handle the route based on its action type
|
|
387
468
|
switch (route.action.type) {
|
|
@@ -634,6 +715,18 @@ export class RouteConnectionHandler {
|
|
|
634
715
|
// No TLS settings - check if this port should use HttpProxy
|
|
635
716
|
const isHttpProxyPort = this.settings.useHttpProxy?.includes(record.localPort);
|
|
636
717
|
|
|
718
|
+
// Debug logging
|
|
719
|
+
if (this.settings.enableDetailedLogging) {
|
|
720
|
+
logger.log('debug', `Checking HttpProxy forwarding: port=${record.localPort}, useHttpProxy=${JSON.stringify(this.settings.useHttpProxy)}, isHttpProxyPort=${isHttpProxyPort}, hasHttpProxy=${!!this.httpProxyBridge.getHttpProxy()}`, {
|
|
721
|
+
connectionId,
|
|
722
|
+
localPort: record.localPort,
|
|
723
|
+
useHttpProxy: this.settings.useHttpProxy,
|
|
724
|
+
isHttpProxyPort,
|
|
725
|
+
hasHttpProxy: !!this.httpProxyBridge.getHttpProxy(),
|
|
726
|
+
component: 'route-handler'
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
|
|
637
730
|
if (isHttpProxyPort && this.httpProxyBridge.getHttpProxy()) {
|
|
638
731
|
// Forward non-TLS connections to HttpProxy if configured
|
|
639
732
|
if (this.settings.enableDetailedLogging) {
|
|
@@ -211,9 +211,10 @@ export class RouteManager extends plugins.EventEmitter {
|
|
|
211
211
|
|
|
212
212
|
/**
|
|
213
213
|
* Check if a client IP is allowed by a route's security settings
|
|
214
|
+
* @deprecated Security is now checked in route-connection-handler.ts after route matching
|
|
214
215
|
*/
|
|
215
216
|
private isClientIpAllowed(route: IRouteConfig, clientIp: string): boolean {
|
|
216
|
-
const security = route.
|
|
217
|
+
const security = route.security;
|
|
217
218
|
|
|
218
219
|
if (!security) {
|
|
219
220
|
return true; // No security settings means allowed
|
|
@@ -330,8 +331,9 @@ export class RouteManager extends plugins.EventEmitter {
|
|
|
330
331
|
clientIp: string;
|
|
331
332
|
path?: string;
|
|
332
333
|
tlsVersion?: string;
|
|
334
|
+
skipDomainCheck?: boolean;
|
|
333
335
|
}): IRouteMatchResult | null {
|
|
334
|
-
const { port, domain, clientIp, path, tlsVersion } = options;
|
|
336
|
+
const { port, domain, clientIp, path, tlsVersion, skipDomainCheck } = options;
|
|
335
337
|
|
|
336
338
|
// Get all routes for this port
|
|
337
339
|
const routesForPort = this.getRoutesForPort(port);
|
|
@@ -340,7 +342,7 @@ export class RouteManager extends plugins.EventEmitter {
|
|
|
340
342
|
for (const route of routesForPort) {
|
|
341
343
|
// Check domain match
|
|
342
344
|
// If the route has domain restrictions and we have a domain to check
|
|
343
|
-
if (route.match.domains) {
|
|
345
|
+
if (route.match.domains && !skipDomainCheck) {
|
|
344
346
|
// If no domain was provided (non-TLS or no SNI), this route doesn't match
|
|
345
347
|
if (!domain) {
|
|
346
348
|
continue;
|
|
@@ -351,6 +353,7 @@ export class RouteManager extends plugins.EventEmitter {
|
|
|
351
353
|
}
|
|
352
354
|
}
|
|
353
355
|
// If route has no domain restrictions, it matches all domains
|
|
356
|
+
// If skipDomainCheck is true, we skip domain validation for HTTP connections
|
|
354
357
|
|
|
355
358
|
// Check path match if specified in both route and request
|
|
356
359
|
if (path && route.match.path) {
|
|
@@ -371,12 +374,8 @@ export class RouteManager extends plugins.EventEmitter {
|
|
|
371
374
|
continue;
|
|
372
375
|
}
|
|
373
376
|
|
|
374
|
-
// Check security settings
|
|
375
|
-
if (!this.isClientIpAllowed(route, clientIp)) {
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
377
|
// All checks passed, this route matches
|
|
378
|
+
// NOTE: Security is checked AFTER route matching in route-connection-handler.ts
|
|
380
379
|
return { route };
|
|
381
380
|
}
|
|
382
381
|
|
|
@@ -625,14 +625,6 @@ export function createNfTablesRoute(
|
|
|
625
625
|
}
|
|
626
626
|
};
|
|
627
627
|
|
|
628
|
-
// Add security if allowed or blocked IPs are specified
|
|
629
|
-
if (options.ipAllowList?.length || options.ipBlockList?.length) {
|
|
630
|
-
action.security = {
|
|
631
|
-
ipAllowList: options.ipAllowList,
|
|
632
|
-
ipBlockList: options.ipBlockList
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
|
|
636
628
|
// Add TLS options if needed
|
|
637
629
|
if (options.useTls) {
|
|
638
630
|
action.tls = {
|
|
@@ -641,11 +633,21 @@ export function createNfTablesRoute(
|
|
|
641
633
|
}
|
|
642
634
|
|
|
643
635
|
// Create the route config
|
|
644
|
-
|
|
636
|
+
const routeConfig: IRouteConfig = {
|
|
645
637
|
name,
|
|
646
638
|
match,
|
|
647
639
|
action
|
|
648
640
|
};
|
|
641
|
+
|
|
642
|
+
// Add security if allowed or blocked IPs are specified
|
|
643
|
+
if (options.ipAllowList?.length || options.ipBlockList?.length) {
|
|
644
|
+
routeConfig.security = {
|
|
645
|
+
ipAllowList: options.ipAllowList,
|
|
646
|
+
ipBlockList: options.ipBlockList
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return routeConfig;
|
|
649
651
|
}
|
|
650
652
|
|
|
651
653
|
/**
|