@push.rocks/smartproxy 15.0.2 → 16.0.2
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/certificate/index.d.ts +10 -4
- package/dist_ts/certificate/index.js +5 -7
- package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
- package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
- package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
- package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
- package/dist_ts/forwarding/config/forwarding-types.js +19 -18
- package/dist_ts/forwarding/config/index.d.ts +4 -2
- package/dist_ts/forwarding/config/index.js +5 -3
- package/dist_ts/forwarding/handlers/base-handler.js +3 -1
- package/dist_ts/forwarding/index.d.ts +5 -6
- package/dist_ts/forwarding/index.js +3 -3
- package/dist_ts/http/models/http-types.js +1 -1
- package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
- package/dist_ts/http/port80/acme-interfaces.js +46 -1
- package/dist_ts/http/port80/port80-handler.d.ts +17 -2
- package/dist_ts/http/port80/port80-handler.js +49 -11
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -61
- package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +118 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +70 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +193 -43
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -5
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -146
- package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +7 -0
- package/dist_ts/proxies/smart-proxy/route-helpers/index.js +9 -0
- package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +54 -1
- package/dist_ts/proxies/smart-proxy/route-helpers.js +102 -1
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +3 -9
- package/dist_ts/proxies/smart-proxy/route-manager.js +3 -115
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +72 -10
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +135 -268
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
- package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +174 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +332 -0
- package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
- package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
- package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +242 -0
- package/package.json +1 -1
- package/readme.md +139 -111
- package/readme.plan.md +164 -312
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/certificate/index.ts +17 -9
- package/ts/certificate/models/certificate-types.ts +37 -16
- package/ts/certificate/providers/cert-provisioner.ts +247 -54
- package/ts/forwarding/config/forwarding-types.ts +79 -107
- package/ts/forwarding/config/index.ts +4 -2
- package/ts/forwarding/handlers/base-handler.ts +4 -2
- package/ts/forwarding/index.ts +3 -2
- package/ts/http/models/http-types.ts +0 -1
- package/ts/http/port80/acme-interfaces.ts +84 -0
- package/ts/http/port80/port80-handler.ts +61 -15
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -64
- package/ts/proxies/smart-proxy/models/route-types.ts +152 -22
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +226 -55
- package/ts/proxies/smart-proxy/route-connection-handler.ts +36 -205
- package/ts/proxies/smart-proxy/route-helpers/index.ts +9 -0
- package/ts/proxies/smart-proxy/route-helpers.ts +165 -11
- package/ts/proxies/smart-proxy/route-manager.ts +3 -130
- package/ts/proxies/smart-proxy/smart-proxy.ts +157 -329
- package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
- package/ts/proxies/smart-proxy/utils/index.ts +40 -0
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +455 -0
- package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
- package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
- package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
- package/ts/proxies/smart-proxy/utils/route-validators.ts +269 -0
- package/ts/forwarding/config/domain-config.ts +0 -28
- package/ts/forwarding/config/domain-manager.ts +0 -283
- package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
- package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
- /package/ts/proxies/smart-proxy/{domain-config-manager.ts → domain-config-manager.ts.bak} +0 -0
|
@@ -5,7 +5,7 @@ import type { TForwardingType } from '../../../forwarding/config/forwarding-type
|
|
|
5
5
|
/**
|
|
6
6
|
* Supported action types for route configurations
|
|
7
7
|
*/
|
|
8
|
-
export type TRouteActionType = 'forward' | 'redirect' | 'block';
|
|
8
|
+
export type TRouteActionType = 'forward' | 'redirect' | 'block' | 'static';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* TLS handling modes for route configurations
|
|
@@ -23,14 +23,15 @@ export type TPortRange = number | number[] | Array<{ from: number; to: number }>
|
|
|
23
23
|
export interface IRouteMatch {
|
|
24
24
|
// Listen on these ports (required)
|
|
25
25
|
ports: TPortRange;
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
// Optional domain patterns to match (default: all domains)
|
|
28
28
|
domains?: string | string[];
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
// Advanced matching criteria
|
|
31
31
|
path?: string; // Match specific paths
|
|
32
32
|
clientIp?: string[]; // Match specific client IPs
|
|
33
33
|
tlsVersion?: string[]; // Match specific TLS versions
|
|
34
|
+
headers?: Record<string, string | RegExp>; // Match specific HTTP headers
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -61,6 +62,25 @@ export interface IRouteRedirect {
|
|
|
61
62
|
status: 301 | 302 | 307 | 308;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Authentication options
|
|
67
|
+
*/
|
|
68
|
+
export interface IRouteAuthentication {
|
|
69
|
+
type: 'basic' | 'digest' | 'oauth' | 'jwt';
|
|
70
|
+
credentials?: {
|
|
71
|
+
username: string;
|
|
72
|
+
password: string;
|
|
73
|
+
}[];
|
|
74
|
+
realm?: string;
|
|
75
|
+
jwtSecret?: string;
|
|
76
|
+
jwtIssuer?: string;
|
|
77
|
+
oauthProvider?: string;
|
|
78
|
+
oauthClientId?: string;
|
|
79
|
+
oauthClientSecret?: string;
|
|
80
|
+
oauthRedirectUri?: string;
|
|
81
|
+
[key: string]: any; // Allow additional auth-specific options
|
|
82
|
+
}
|
|
83
|
+
|
|
64
84
|
/**
|
|
65
85
|
* Security options for route actions
|
|
66
86
|
*/
|
|
@@ -68,10 +88,31 @@ export interface IRouteSecurity {
|
|
|
68
88
|
allowedIps?: string[];
|
|
69
89
|
blockedIps?: string[];
|
|
70
90
|
maxConnections?: number;
|
|
71
|
-
authentication?:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
authentication?: IRouteAuthentication;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Static file server configuration
|
|
96
|
+
*/
|
|
97
|
+
export interface IRouteStaticFiles {
|
|
98
|
+
root: string;
|
|
99
|
+
index?: string[];
|
|
100
|
+
headers?: Record<string, string>;
|
|
101
|
+
directory?: string;
|
|
102
|
+
indexFiles?: string[];
|
|
103
|
+
cacheControl?: string;
|
|
104
|
+
expires?: number;
|
|
105
|
+
followSymlinks?: boolean;
|
|
106
|
+
disableDirectoryListing?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Test route response configuration
|
|
111
|
+
*/
|
|
112
|
+
export interface IRouteTestResponse {
|
|
113
|
+
status: number;
|
|
114
|
+
headers: Record<string, string>;
|
|
115
|
+
body: string;
|
|
75
116
|
}
|
|
76
117
|
|
|
77
118
|
/**
|
|
@@ -81,47 +122,136 @@ export interface IRouteAdvanced {
|
|
|
81
122
|
timeout?: number;
|
|
82
123
|
headers?: Record<string, string>;
|
|
83
124
|
keepAlive?: boolean;
|
|
125
|
+
staticFiles?: IRouteStaticFiles;
|
|
126
|
+
testResponse?: IRouteTestResponse;
|
|
84
127
|
// Additional advanced options would go here
|
|
85
128
|
}
|
|
86
129
|
|
|
130
|
+
/**
|
|
131
|
+
* WebSocket configuration
|
|
132
|
+
*/
|
|
133
|
+
export interface IRouteWebSocket {
|
|
134
|
+
enabled: boolean;
|
|
135
|
+
pingInterval?: number;
|
|
136
|
+
pingTimeout?: number;
|
|
137
|
+
maxPayloadSize?: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Load balancing configuration
|
|
142
|
+
*/
|
|
143
|
+
export interface IRouteLoadBalancing {
|
|
144
|
+
algorithm: 'round-robin' | 'least-connections' | 'ip-hash';
|
|
145
|
+
healthCheck?: {
|
|
146
|
+
path: string;
|
|
147
|
+
interval: number;
|
|
148
|
+
timeout: number;
|
|
149
|
+
unhealthyThreshold: number;
|
|
150
|
+
healthyThreshold: number;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
87
154
|
/**
|
|
88
155
|
* Action configuration for route handling
|
|
89
156
|
*/
|
|
90
157
|
export interface IRouteAction {
|
|
91
158
|
// Basic routing
|
|
92
159
|
type: TRouteActionType;
|
|
93
|
-
|
|
160
|
+
|
|
94
161
|
// Target for forwarding
|
|
95
162
|
target?: IRouteTarget;
|
|
96
|
-
|
|
163
|
+
|
|
97
164
|
// TLS handling
|
|
98
165
|
tls?: IRouteTls;
|
|
99
|
-
|
|
166
|
+
|
|
100
167
|
// For redirects
|
|
101
168
|
redirect?: IRouteRedirect;
|
|
102
|
-
|
|
169
|
+
|
|
170
|
+
// For static files
|
|
171
|
+
static?: IRouteStaticFiles;
|
|
172
|
+
|
|
173
|
+
// WebSocket support
|
|
174
|
+
websocket?: IRouteWebSocket;
|
|
175
|
+
|
|
176
|
+
// Load balancing options
|
|
177
|
+
loadBalancing?: IRouteLoadBalancing;
|
|
178
|
+
|
|
103
179
|
// Security options
|
|
104
180
|
security?: IRouteSecurity;
|
|
105
|
-
|
|
181
|
+
|
|
106
182
|
// Advanced options
|
|
107
183
|
advanced?: IRouteAdvanced;
|
|
108
184
|
}
|
|
109
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Rate limiting configuration
|
|
188
|
+
*/
|
|
189
|
+
export interface IRouteRateLimit {
|
|
190
|
+
enabled: boolean;
|
|
191
|
+
maxRequests: number;
|
|
192
|
+
window: number; // Time window in seconds
|
|
193
|
+
keyBy?: 'ip' | 'path' | 'header';
|
|
194
|
+
headerName?: string;
|
|
195
|
+
errorMessage?: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Security features for routes
|
|
200
|
+
*/
|
|
201
|
+
export interface IRouteSecurity {
|
|
202
|
+
rateLimit?: IRouteRateLimit;
|
|
203
|
+
basicAuth?: {
|
|
204
|
+
enabled: boolean;
|
|
205
|
+
users: Array<{ username: string; password: string }>;
|
|
206
|
+
realm?: string;
|
|
207
|
+
excludePaths?: string[];
|
|
208
|
+
};
|
|
209
|
+
jwtAuth?: {
|
|
210
|
+
enabled: boolean;
|
|
211
|
+
secret: string;
|
|
212
|
+
algorithm?: string;
|
|
213
|
+
issuer?: string;
|
|
214
|
+
audience?: string;
|
|
215
|
+
expiresIn?: number;
|
|
216
|
+
excludePaths?: string[];
|
|
217
|
+
};
|
|
218
|
+
ipAllowList?: string[];
|
|
219
|
+
ipBlockList?: string[];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Headers configuration
|
|
224
|
+
*/
|
|
225
|
+
export interface IRouteHeaders {
|
|
226
|
+
request?: Record<string, string>;
|
|
227
|
+
response?: Record<string, string>;
|
|
228
|
+
}
|
|
229
|
+
|
|
110
230
|
/**
|
|
111
231
|
* The core unified configuration interface
|
|
112
232
|
*/
|
|
113
233
|
export interface IRouteConfig {
|
|
234
|
+
// Unique identifier
|
|
235
|
+
id?: string;
|
|
236
|
+
|
|
114
237
|
// What to match
|
|
115
238
|
match: IRouteMatch;
|
|
116
|
-
|
|
239
|
+
|
|
117
240
|
// What to do with matched traffic
|
|
118
241
|
action: IRouteAction;
|
|
119
|
-
|
|
242
|
+
|
|
243
|
+
// Custom headers
|
|
244
|
+
headers?: IRouteHeaders;
|
|
245
|
+
|
|
246
|
+
// Security features
|
|
247
|
+
security?: IRouteSecurity;
|
|
248
|
+
|
|
120
249
|
// Optional metadata
|
|
121
250
|
name?: string; // Human-readable name for this route
|
|
122
251
|
description?: string; // Description of the route's purpose
|
|
123
252
|
priority?: number; // Controls matching order (higher = matched first)
|
|
124
253
|
tags?: string[]; // Arbitrary tags for categorization
|
|
254
|
+
enabled?: boolean; // Whether the route is active (default: true)
|
|
125
255
|
}
|
|
126
256
|
|
|
127
257
|
/**
|
|
@@ -130,7 +260,7 @@ export interface IRouteConfig {
|
|
|
130
260
|
export interface IRoutedSmartProxyOptions {
|
|
131
261
|
// The unified configuration array (required)
|
|
132
262
|
routes: IRouteConfig[];
|
|
133
|
-
|
|
263
|
+
|
|
134
264
|
// Global/default settings
|
|
135
265
|
defaults?: {
|
|
136
266
|
target?: {
|
|
@@ -141,10 +271,10 @@ export interface IRoutedSmartProxyOptions {
|
|
|
141
271
|
tls?: IRouteTls;
|
|
142
272
|
// ...other defaults
|
|
143
273
|
};
|
|
144
|
-
|
|
274
|
+
|
|
145
275
|
// Other global settings remain (acme, etc.)
|
|
146
276
|
acme?: IAcmeOptions;
|
|
147
|
-
|
|
277
|
+
|
|
148
278
|
// Connection timeouts and other global settings
|
|
149
279
|
initialDataTimeout?: number;
|
|
150
280
|
socketTimeout?: number;
|
|
@@ -152,13 +282,13 @@ export interface IRoutedSmartProxyOptions {
|
|
|
152
282
|
maxConnectionLifetime?: number;
|
|
153
283
|
inactivityTimeout?: number;
|
|
154
284
|
gracefulShutdownTimeout?: number;
|
|
155
|
-
|
|
285
|
+
|
|
156
286
|
// Socket optimization settings
|
|
157
287
|
noDelay?: boolean;
|
|
158
288
|
keepAlive?: boolean;
|
|
159
289
|
keepAliveInitialDelay?: number;
|
|
160
290
|
maxPendingDataSize?: number;
|
|
161
|
-
|
|
291
|
+
|
|
162
292
|
// Enhanced features
|
|
163
293
|
disableInactivityCheck?: boolean;
|
|
164
294
|
enableKeepAliveProbes?: boolean;
|
|
@@ -166,16 +296,16 @@ export interface IRoutedSmartProxyOptions {
|
|
|
166
296
|
enableTlsDebugLogging?: boolean;
|
|
167
297
|
enableRandomizedTimeouts?: boolean;
|
|
168
298
|
allowSessionTicket?: boolean;
|
|
169
|
-
|
|
299
|
+
|
|
170
300
|
// Rate limiting and security
|
|
171
301
|
maxConnectionsPerIP?: number;
|
|
172
302
|
connectionRateLimitPerMinute?: number;
|
|
173
|
-
|
|
303
|
+
|
|
174
304
|
// Enhanced keep-alive settings
|
|
175
305
|
keepAliveTreatment?: 'standard' | 'extended' | 'immortal';
|
|
176
306
|
keepAliveInactivityMultiplier?: number;
|
|
177
307
|
extendedKeepAliveLifetime?: number;
|
|
178
|
-
|
|
308
|
+
|
|
179
309
|
/**
|
|
180
310
|
* Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges,
|
|
181
311
|
* or a static certificate object for immediate provisioning.
|
|
@@ -4,10 +4,19 @@ import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
|
4
4
|
import { Port80HandlerEvents } from '../../core/models/common-types.js';
|
|
5
5
|
import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
|
|
6
6
|
import type { ICertificateData } from '../../certificate/models/certificate-types.js';
|
|
7
|
-
import type { IConnectionRecord, ISmartProxyOptions
|
|
7
|
+
import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
|
|
8
|
+
import type { IRouteConfig } from './models/route-types.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Manages NetworkProxy integration for TLS termination
|
|
12
|
+
*
|
|
13
|
+
* NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
|
|
14
|
+
* It directly maps route configurations to NetworkProxy configuration format and manages
|
|
15
|
+
* certificate provisioning through Port80Handler when ACME is enabled.
|
|
16
|
+
*
|
|
17
|
+
* It is used by SmartProxy for routes that have:
|
|
18
|
+
* - TLS mode of 'terminate' or 'terminate-and-reencrypt'
|
|
19
|
+
* - Certificate set to 'auto' or custom certificate
|
|
11
20
|
*/
|
|
12
21
|
export class NetworkProxyBridge {
|
|
13
22
|
private networkProxy: NetworkProxy | null = null;
|
|
@@ -58,8 +67,8 @@ export class NetworkProxyBridge {
|
|
|
58
67
|
this.networkProxy.setExternalPort80Handler(this.port80Handler);
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
//
|
|
62
|
-
await this.
|
|
70
|
+
// Apply route configurations to NetworkProxy
|
|
71
|
+
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
|
63
72
|
}
|
|
64
73
|
}
|
|
65
74
|
|
|
@@ -147,35 +156,90 @@ export class NetworkProxyBridge {
|
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
/**
|
|
150
|
-
* Register domains with Port80Handler
|
|
159
|
+
* Register domains from routes with Port80Handler for certificate management
|
|
160
|
+
*
|
|
161
|
+
* Extracts domains from routes that require TLS termination and registers them
|
|
162
|
+
* with the Port80Handler for certificate issuance and renewal.
|
|
163
|
+
*
|
|
164
|
+
* @param routes The route configurations to extract domains from
|
|
151
165
|
*/
|
|
152
|
-
public registerDomainsWithPort80Handler(
|
|
166
|
+
public registerDomainsWithPort80Handler(routes: IRouteConfig[]): void {
|
|
153
167
|
if (!this.port80Handler) {
|
|
154
168
|
console.log('Cannot register domains - Port80Handler not initialized');
|
|
155
169
|
return;
|
|
156
170
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
|
|
172
|
+
// Extract domains from routes that require TLS termination
|
|
173
|
+
const domainsToRegister = new Set<string>();
|
|
174
|
+
|
|
175
|
+
for (const route of routes) {
|
|
176
|
+
// Skip routes without domains or TLS configuration
|
|
177
|
+
if (!route.match.domains || !route.action.tls) continue;
|
|
178
|
+
|
|
179
|
+
// Only register domains for routes that terminate TLS
|
|
180
|
+
if (route.action.tls.mode !== 'terminate' && route.action.tls.mode !== 'terminate-and-reencrypt') continue;
|
|
181
|
+
|
|
182
|
+
// Extract domains from route
|
|
183
|
+
const domains = Array.isArray(route.match.domains)
|
|
184
|
+
? route.match.domains
|
|
185
|
+
: [route.match.domains];
|
|
186
|
+
|
|
187
|
+
// Add each domain to the set (avoiding duplicates)
|
|
188
|
+
for (const domain of domains) {
|
|
189
|
+
// Skip wildcards
|
|
190
|
+
if (domain.includes('*')) {
|
|
191
|
+
console.log(`Skipping wildcard domain for ACME: ${domain}`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
domainsToRegister.add(domain);
|
|
163
196
|
}
|
|
164
|
-
|
|
165
|
-
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Register each unique domain with Port80Handler
|
|
200
|
+
for (const domain of domainsToRegister) {
|
|
166
201
|
try {
|
|
167
202
|
this.port80Handler.addDomain({
|
|
168
203
|
domainName: domain,
|
|
169
204
|
sslRedirect: true,
|
|
170
|
-
acmeMaintenance: true
|
|
205
|
+
acmeMaintenance: true,
|
|
206
|
+
// Include route reference if we can find it
|
|
207
|
+
routeReference: this.findRouteReferenceForDomain(domain, routes)
|
|
171
208
|
});
|
|
172
|
-
|
|
209
|
+
|
|
173
210
|
console.log(`Registered domain with Port80Handler: ${domain}`);
|
|
174
211
|
} catch (err) {
|
|
175
212
|
console.log(`Error registering domain ${domain} with Port80Handler: ${err}`);
|
|
176
213
|
}
|
|
177
214
|
}
|
|
178
215
|
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Finds the route reference for a given domain
|
|
219
|
+
*
|
|
220
|
+
* @param domain The domain to find a route reference for
|
|
221
|
+
* @param routes The routes to search
|
|
222
|
+
* @returns The route reference if found, undefined otherwise
|
|
223
|
+
*/
|
|
224
|
+
private findRouteReferenceForDomain(domain: string, routes: IRouteConfig[]): { routeId?: string; routeName?: string } | undefined {
|
|
225
|
+
// Find the first route that matches this domain
|
|
226
|
+
for (const route of routes) {
|
|
227
|
+
if (!route.match.domains) continue;
|
|
228
|
+
|
|
229
|
+
const domains = Array.isArray(route.match.domains)
|
|
230
|
+
? route.match.domains
|
|
231
|
+
: [route.match.domains];
|
|
232
|
+
|
|
233
|
+
if (domains.includes(domain)) {
|
|
234
|
+
return {
|
|
235
|
+
routeId: undefined, // No explicit IDs in our current routes
|
|
236
|
+
routeName: route.name
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
179
243
|
|
|
180
244
|
/**
|
|
181
245
|
* Forwards a TLS connection to a NetworkProxy for handling
|
|
@@ -249,9 +313,19 @@ export class NetworkProxyBridge {
|
|
|
249
313
|
}
|
|
250
314
|
|
|
251
315
|
/**
|
|
252
|
-
* Synchronizes
|
|
316
|
+
* Synchronizes routes to NetworkProxy
|
|
317
|
+
*
|
|
318
|
+
* This method directly maps route configurations to NetworkProxy format and updates
|
|
319
|
+
* the NetworkProxy with these configurations. It handles:
|
|
320
|
+
*
|
|
321
|
+
* - Extracting domain, target, and certificate information from routes
|
|
322
|
+
* - Converting TLS mode settings to NetworkProxy configuration
|
|
323
|
+
* - Applying security and advanced settings
|
|
324
|
+
* - Registering domains for ACME certificate provisioning when needed
|
|
325
|
+
*
|
|
326
|
+
* @param routes The route configurations to sync to NetworkProxy
|
|
253
327
|
*/
|
|
254
|
-
public async
|
|
328
|
+
public async syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise<void> {
|
|
255
329
|
if (!this.networkProxy) {
|
|
256
330
|
console.log('Cannot sync configurations - NetworkProxy not initialized');
|
|
257
331
|
return;
|
|
@@ -262,9 +336,9 @@ export class NetworkProxyBridge {
|
|
|
262
336
|
// Import fs directly since it's not in plugins
|
|
263
337
|
const fs = await import('fs');
|
|
264
338
|
|
|
265
|
-
let
|
|
339
|
+
let defaultCertPair;
|
|
266
340
|
try {
|
|
267
|
-
|
|
341
|
+
defaultCertPair = {
|
|
268
342
|
key: fs.readFileSync('assets/certs/key.pem', 'utf8'),
|
|
269
343
|
cert: fs.readFileSync('assets/certs/cert.pem', 'utf8'),
|
|
270
344
|
};
|
|
@@ -276,49 +350,130 @@ export class NetworkProxyBridge {
|
|
|
276
350
|
|
|
277
351
|
// Use empty placeholders - NetworkProxy will use its internal defaults
|
|
278
352
|
// or ACME will generate proper ones if enabled
|
|
279
|
-
|
|
353
|
+
defaultCertPair = {
|
|
280
354
|
key: '',
|
|
281
355
|
cert: '',
|
|
282
356
|
};
|
|
283
357
|
}
|
|
284
358
|
|
|
285
|
-
//
|
|
286
|
-
const proxyConfigs = this.
|
|
287
|
-
this.settings.domainConfigs,
|
|
288
|
-
certPair
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
// Log ACME-eligible domains
|
|
292
|
-
const acmeEnabled = !!this.settings.acme?.enabled;
|
|
293
|
-
if (acmeEnabled) {
|
|
294
|
-
const acmeEligibleDomains = proxyConfigs
|
|
295
|
-
.filter((config) => !config.hostName.includes('*')) // Exclude wildcards
|
|
296
|
-
.map((config) => config.hostName);
|
|
297
|
-
|
|
298
|
-
if (acmeEligibleDomains.length > 0) {
|
|
299
|
-
console.log(`Domains eligible for ACME certificates: ${acmeEligibleDomains.join(', ')}`);
|
|
300
|
-
|
|
301
|
-
// Register these domains with Port80Handler if available
|
|
302
|
-
if (this.port80Handler) {
|
|
303
|
-
this.registerDomainsWithPort80Handler(acmeEligibleDomains);
|
|
304
|
-
}
|
|
305
|
-
} else {
|
|
306
|
-
console.log('No domains eligible for ACME certificates found in configuration');
|
|
307
|
-
}
|
|
308
|
-
}
|
|
359
|
+
// Map routes directly to NetworkProxy configs
|
|
360
|
+
const proxyConfigs = this.mapRoutesToNetworkProxyConfigs(routes, defaultCertPair);
|
|
309
361
|
|
|
310
|
-
// Update
|
|
362
|
+
// Update the proxy configs
|
|
311
363
|
await this.networkProxy.updateProxyConfigs(proxyConfigs);
|
|
312
|
-
console.log(`
|
|
364
|
+
console.log(`Synced ${proxyConfigs.length} configurations to NetworkProxy`);
|
|
365
|
+
|
|
366
|
+
// Register domains with Port80Handler for certificate issuance
|
|
367
|
+
if (this.port80Handler) {
|
|
368
|
+
this.registerDomainsWithPort80Handler(routes);
|
|
369
|
+
}
|
|
313
370
|
} catch (err) {
|
|
314
|
-
console.log(`
|
|
371
|
+
console.log(`Error syncing routes to NetworkProxy: ${err}`);
|
|
315
372
|
}
|
|
316
373
|
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Map routes directly to NetworkProxy configuration format
|
|
377
|
+
*
|
|
378
|
+
* This method directly maps route configurations to NetworkProxy's format
|
|
379
|
+
* without any intermediate domain-based representation. It processes each route
|
|
380
|
+
* and creates appropriate NetworkProxy configs for domains that require TLS termination.
|
|
381
|
+
*
|
|
382
|
+
* @param routes Array of route configurations to map
|
|
383
|
+
* @param defaultCertPair Default certificate to use if no custom certificate is specified
|
|
384
|
+
* @returns Array of NetworkProxy configurations
|
|
385
|
+
*/
|
|
386
|
+
public mapRoutesToNetworkProxyConfigs(
|
|
387
|
+
routes: IRouteConfig[],
|
|
388
|
+
defaultCertPair: { key: string; cert: string }
|
|
389
|
+
): plugins.tsclass.network.IReverseProxyConfig[] {
|
|
390
|
+
const configs: plugins.tsclass.network.IReverseProxyConfig[] = [];
|
|
391
|
+
|
|
392
|
+
for (const route of routes) {
|
|
393
|
+
// Skip routes without domains
|
|
394
|
+
if (!route.match.domains) continue;
|
|
395
|
+
|
|
396
|
+
// Skip non-forward routes
|
|
397
|
+
if (route.action.type !== 'forward') continue;
|
|
398
|
+
|
|
399
|
+
// Skip routes without TLS configuration
|
|
400
|
+
if (!route.action.tls || !route.action.target) continue;
|
|
401
|
+
|
|
402
|
+
// Skip routes that don't require TLS termination
|
|
403
|
+
if (route.action.tls.mode !== 'terminate' && route.action.tls.mode !== 'terminate-and-reencrypt') continue;
|
|
404
|
+
|
|
405
|
+
// Get domains from route
|
|
406
|
+
const domains = Array.isArray(route.match.domains)
|
|
407
|
+
? route.match.domains
|
|
408
|
+
: [route.match.domains];
|
|
409
|
+
|
|
410
|
+
// Create a config for each domain
|
|
411
|
+
for (const domain of domains) {
|
|
412
|
+
// Get certificate
|
|
413
|
+
let certKey = defaultCertPair.key;
|
|
414
|
+
let certCert = defaultCertPair.cert;
|
|
415
|
+
|
|
416
|
+
// Use custom certificate if specified
|
|
417
|
+
if (route.action.tls.certificate !== 'auto' && typeof route.action.tls.certificate === 'object') {
|
|
418
|
+
certKey = route.action.tls.certificate.key;
|
|
419
|
+
certCert = route.action.tls.certificate.cert;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Determine target hosts and ports
|
|
423
|
+
const targetHosts = Array.isArray(route.action.target.host)
|
|
424
|
+
? route.action.target.host
|
|
425
|
+
: [route.action.target.host];
|
|
426
|
+
|
|
427
|
+
const targetPort = route.action.target.port;
|
|
428
|
+
|
|
429
|
+
// Create the NetworkProxy config
|
|
430
|
+
const config: plugins.tsclass.network.IReverseProxyConfig = {
|
|
431
|
+
hostName: domain,
|
|
432
|
+
privateKey: certKey,
|
|
433
|
+
publicKey: certCert,
|
|
434
|
+
destinationIps: targetHosts,
|
|
435
|
+
destinationPorts: [targetPort]
|
|
436
|
+
// Note: We can't include additional metadata as it's not supported in the interface
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
configs.push(config);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return configs;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @deprecated This method is kept for backward compatibility.
|
|
448
|
+
* Use mapRoutesToNetworkProxyConfigs() instead.
|
|
449
|
+
*/
|
|
450
|
+
public convertRoutesToNetworkProxyConfigs(
|
|
451
|
+
routes: IRouteConfig[],
|
|
452
|
+
defaultCertPair: { key: string; cert: string }
|
|
453
|
+
): plugins.tsclass.network.IReverseProxyConfig[] {
|
|
454
|
+
return this.mapRoutesToNetworkProxyConfigs(routes, defaultCertPair);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
459
|
+
* Use syncRoutesToNetworkProxy() instead.
|
|
460
|
+
*
|
|
461
|
+
* This legacy method exists only for backward compatibility and
|
|
462
|
+
* simply forwards to syncRoutesToNetworkProxy().
|
|
463
|
+
*/
|
|
464
|
+
public async syncDomainConfigsToNetworkProxy(): Promise<void> {
|
|
465
|
+
console.log('DEPRECATED: Method syncDomainConfigsToNetworkProxy will be removed in a future version.');
|
|
466
|
+
console.log('Please use syncRoutesToNetworkProxy() instead for direct route-based configuration.');
|
|
467
|
+
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
|
468
|
+
}
|
|
317
469
|
|
|
318
470
|
/**
|
|
319
471
|
* Request a certificate for a specific domain
|
|
472
|
+
*
|
|
473
|
+
* @param domain The domain to request a certificate for
|
|
474
|
+
* @param routeName Optional route name to associate with this certificate
|
|
320
475
|
*/
|
|
321
|
-
public async requestCertificate(domain: string): Promise<boolean> {
|
|
476
|
+
public async requestCertificate(domain: string, routeName?: string): Promise<boolean> {
|
|
322
477
|
// Delegate to Port80Handler if available
|
|
323
478
|
if (this.port80Handler) {
|
|
324
479
|
try {
|
|
@@ -328,14 +483,30 @@ export class NetworkProxyBridge {
|
|
|
328
483
|
console.log(`Certificate already exists for ${domain}`);
|
|
329
484
|
return true;
|
|
330
485
|
}
|
|
331
|
-
|
|
332
|
-
//
|
|
333
|
-
|
|
486
|
+
|
|
487
|
+
// Build the domain options
|
|
488
|
+
const domainOptions: any = {
|
|
334
489
|
domainName: domain,
|
|
335
490
|
sslRedirect: true,
|
|
336
|
-
acmeMaintenance: true
|
|
337
|
-
}
|
|
338
|
-
|
|
491
|
+
acmeMaintenance: true,
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
// Add route reference if available
|
|
495
|
+
if (routeName) {
|
|
496
|
+
domainOptions.routeReference = {
|
|
497
|
+
routeName
|
|
498
|
+
};
|
|
499
|
+
} else {
|
|
500
|
+
// Try to find a route reference from the current routes
|
|
501
|
+
const routeReference = this.findRouteReferenceForDomain(domain, this.settings.routes || []);
|
|
502
|
+
if (routeReference) {
|
|
503
|
+
domainOptions.routeReference = routeReference;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Register the domain for certificate issuance
|
|
508
|
+
this.port80Handler.addDomain(domainOptions);
|
|
509
|
+
|
|
339
510
|
console.log(`Domain ${domain} registered for certificate issuance`);
|
|
340
511
|
return true;
|
|
341
512
|
} catch (err) {
|
|
@@ -343,7 +514,7 @@ export class NetworkProxyBridge {
|
|
|
343
514
|
return false;
|
|
344
515
|
}
|
|
345
516
|
}
|
|
346
|
-
|
|
517
|
+
|
|
347
518
|
// Fall back to NetworkProxy if Port80Handler is not available
|
|
348
519
|
if (!this.networkProxy) {
|
|
349
520
|
console.log('Cannot request certificate - NetworkProxy not initialized');
|