@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
|
@@ -2,7 +2,7 @@ import type { IAcmeOptions } from '../../../certificate/models/certificate-types
|
|
|
2
2
|
/**
|
|
3
3
|
* Supported action types for route configurations
|
|
4
4
|
*/
|
|
5
|
-
export type TRouteActionType = 'forward' | 'redirect' | 'block';
|
|
5
|
+
export type TRouteActionType = 'forward' | 'redirect' | 'block' | 'static';
|
|
6
6
|
/**
|
|
7
7
|
* TLS handling modes for route configurations
|
|
8
8
|
*/
|
|
@@ -23,6 +23,7 @@ export interface IRouteMatch {
|
|
|
23
23
|
path?: string;
|
|
24
24
|
clientIp?: string[];
|
|
25
25
|
tlsVersion?: string[];
|
|
26
|
+
headers?: Record<string, string | RegExp>;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Target configuration for forwarding
|
|
@@ -49,6 +50,24 @@ export interface IRouteRedirect {
|
|
|
49
50
|
to: string;
|
|
50
51
|
status: 301 | 302 | 307 | 308;
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Authentication options
|
|
55
|
+
*/
|
|
56
|
+
export interface IRouteAuthentication {
|
|
57
|
+
type: 'basic' | 'digest' | 'oauth' | 'jwt';
|
|
58
|
+
credentials?: {
|
|
59
|
+
username: string;
|
|
60
|
+
password: string;
|
|
61
|
+
}[];
|
|
62
|
+
realm?: string;
|
|
63
|
+
jwtSecret?: string;
|
|
64
|
+
jwtIssuer?: string;
|
|
65
|
+
oauthProvider?: string;
|
|
66
|
+
oauthClientId?: string;
|
|
67
|
+
oauthClientSecret?: string;
|
|
68
|
+
oauthRedirectUri?: string;
|
|
69
|
+
[key: string]: any;
|
|
70
|
+
}
|
|
52
71
|
/**
|
|
53
72
|
* Security options for route actions
|
|
54
73
|
*/
|
|
@@ -56,9 +75,29 @@ export interface IRouteSecurity {
|
|
|
56
75
|
allowedIps?: string[];
|
|
57
76
|
blockedIps?: string[];
|
|
58
77
|
maxConnections?: number;
|
|
59
|
-
authentication?:
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
authentication?: IRouteAuthentication;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Static file server configuration
|
|
82
|
+
*/
|
|
83
|
+
export interface IRouteStaticFiles {
|
|
84
|
+
root: string;
|
|
85
|
+
index?: string[];
|
|
86
|
+
headers?: Record<string, string>;
|
|
87
|
+
directory?: string;
|
|
88
|
+
indexFiles?: string[];
|
|
89
|
+
cacheControl?: string;
|
|
90
|
+
expires?: number;
|
|
91
|
+
followSymlinks?: boolean;
|
|
92
|
+
disableDirectoryListing?: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Test route response configuration
|
|
96
|
+
*/
|
|
97
|
+
export interface IRouteTestResponse {
|
|
98
|
+
status: number;
|
|
99
|
+
headers: Record<string, string>;
|
|
100
|
+
body: string;
|
|
62
101
|
}
|
|
63
102
|
/**
|
|
64
103
|
* Advanced options for route actions
|
|
@@ -67,6 +106,30 @@ export interface IRouteAdvanced {
|
|
|
67
106
|
timeout?: number;
|
|
68
107
|
headers?: Record<string, string>;
|
|
69
108
|
keepAlive?: boolean;
|
|
109
|
+
staticFiles?: IRouteStaticFiles;
|
|
110
|
+
testResponse?: IRouteTestResponse;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* WebSocket configuration
|
|
114
|
+
*/
|
|
115
|
+
export interface IRouteWebSocket {
|
|
116
|
+
enabled: boolean;
|
|
117
|
+
pingInterval?: number;
|
|
118
|
+
pingTimeout?: number;
|
|
119
|
+
maxPayloadSize?: number;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Load balancing configuration
|
|
123
|
+
*/
|
|
124
|
+
export interface IRouteLoadBalancing {
|
|
125
|
+
algorithm: 'round-robin' | 'least-connections' | 'ip-hash';
|
|
126
|
+
healthCheck?: {
|
|
127
|
+
path: string;
|
|
128
|
+
interval: number;
|
|
129
|
+
timeout: number;
|
|
130
|
+
unhealthyThreshold: number;
|
|
131
|
+
healthyThreshold: number;
|
|
132
|
+
};
|
|
70
133
|
}
|
|
71
134
|
/**
|
|
72
135
|
* Action configuration for route handling
|
|
@@ -76,19 +139,70 @@ export interface IRouteAction {
|
|
|
76
139
|
target?: IRouteTarget;
|
|
77
140
|
tls?: IRouteTls;
|
|
78
141
|
redirect?: IRouteRedirect;
|
|
142
|
+
static?: IRouteStaticFiles;
|
|
143
|
+
websocket?: IRouteWebSocket;
|
|
144
|
+
loadBalancing?: IRouteLoadBalancing;
|
|
79
145
|
security?: IRouteSecurity;
|
|
80
146
|
advanced?: IRouteAdvanced;
|
|
81
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Rate limiting configuration
|
|
150
|
+
*/
|
|
151
|
+
export interface IRouteRateLimit {
|
|
152
|
+
enabled: boolean;
|
|
153
|
+
maxRequests: number;
|
|
154
|
+
window: number;
|
|
155
|
+
keyBy?: 'ip' | 'path' | 'header';
|
|
156
|
+
headerName?: string;
|
|
157
|
+
errorMessage?: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Security features for routes
|
|
161
|
+
*/
|
|
162
|
+
export interface IRouteSecurity {
|
|
163
|
+
rateLimit?: IRouteRateLimit;
|
|
164
|
+
basicAuth?: {
|
|
165
|
+
enabled: boolean;
|
|
166
|
+
users: Array<{
|
|
167
|
+
username: string;
|
|
168
|
+
password: string;
|
|
169
|
+
}>;
|
|
170
|
+
realm?: string;
|
|
171
|
+
excludePaths?: string[];
|
|
172
|
+
};
|
|
173
|
+
jwtAuth?: {
|
|
174
|
+
enabled: boolean;
|
|
175
|
+
secret: string;
|
|
176
|
+
algorithm?: string;
|
|
177
|
+
issuer?: string;
|
|
178
|
+
audience?: string;
|
|
179
|
+
expiresIn?: number;
|
|
180
|
+
excludePaths?: string[];
|
|
181
|
+
};
|
|
182
|
+
ipAllowList?: string[];
|
|
183
|
+
ipBlockList?: string[];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Headers configuration
|
|
187
|
+
*/
|
|
188
|
+
export interface IRouteHeaders {
|
|
189
|
+
request?: Record<string, string>;
|
|
190
|
+
response?: Record<string, string>;
|
|
191
|
+
}
|
|
82
192
|
/**
|
|
83
193
|
* The core unified configuration interface
|
|
84
194
|
*/
|
|
85
195
|
export interface IRouteConfig {
|
|
196
|
+
id?: string;
|
|
86
197
|
match: IRouteMatch;
|
|
87
198
|
action: IRouteAction;
|
|
199
|
+
headers?: IRouteHeaders;
|
|
200
|
+
security?: IRouteSecurity;
|
|
88
201
|
name?: string;
|
|
89
202
|
description?: string;
|
|
90
203
|
priority?: number;
|
|
91
204
|
tags?: string[];
|
|
205
|
+
enabled?: boolean;
|
|
92
206
|
}
|
|
93
207
|
/**
|
|
94
208
|
* Unified SmartProxy options with routes-based configuration
|
|
@@ -3,8 +3,17 @@ import { NetworkProxy } from '../network-proxy/index.js';
|
|
|
3
3
|
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
4
4
|
import type { ICertificateData } from '../../certificate/models/certificate-types.js';
|
|
5
5
|
import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
|
|
6
|
+
import type { IRouteConfig } from './models/route-types.js';
|
|
6
7
|
/**
|
|
7
8
|
* Manages NetworkProxy integration for TLS termination
|
|
9
|
+
*
|
|
10
|
+
* NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
|
|
11
|
+
* It directly maps route configurations to NetworkProxy configuration format and manages
|
|
12
|
+
* certificate provisioning through Port80Handler when ACME is enabled.
|
|
13
|
+
*
|
|
14
|
+
* It is used by SmartProxy for routes that have:
|
|
15
|
+
* - TLS mode of 'terminate' or 'terminate-and-reencrypt'
|
|
16
|
+
* - Certificate set to 'auto' or custom certificate
|
|
8
17
|
*/
|
|
9
18
|
export declare class NetworkProxyBridge {
|
|
10
19
|
private settings;
|
|
@@ -44,19 +53,76 @@ export declare class NetworkProxyBridge {
|
|
|
44
53
|
*/
|
|
45
54
|
stop(): Promise<void>;
|
|
46
55
|
/**
|
|
47
|
-
* Register domains with Port80Handler
|
|
56
|
+
* Register domains from routes with Port80Handler for certificate management
|
|
57
|
+
*
|
|
58
|
+
* Extracts domains from routes that require TLS termination and registers them
|
|
59
|
+
* with the Port80Handler for certificate issuance and renewal.
|
|
60
|
+
*
|
|
61
|
+
* @param routes The route configurations to extract domains from
|
|
48
62
|
*/
|
|
49
|
-
registerDomainsWithPort80Handler(
|
|
63
|
+
registerDomainsWithPort80Handler(routes: IRouteConfig[]): void;
|
|
64
|
+
/**
|
|
65
|
+
* Finds the route reference for a given domain
|
|
66
|
+
*
|
|
67
|
+
* @param domain The domain to find a route reference for
|
|
68
|
+
* @param routes The routes to search
|
|
69
|
+
* @returns The route reference if found, undefined otherwise
|
|
70
|
+
*/
|
|
71
|
+
private findRouteReferenceForDomain;
|
|
50
72
|
/**
|
|
51
73
|
* Forwards a TLS connection to a NetworkProxy for handling
|
|
52
74
|
*/
|
|
53
75
|
forwardToNetworkProxy(connectionId: string, socket: plugins.net.Socket, record: IConnectionRecord, initialData: Buffer, customProxyPort?: number, onError?: (reason: string) => void): void;
|
|
54
76
|
/**
|
|
55
|
-
* Synchronizes
|
|
77
|
+
* Synchronizes routes to NetworkProxy
|
|
78
|
+
*
|
|
79
|
+
* This method directly maps route configurations to NetworkProxy format and updates
|
|
80
|
+
* the NetworkProxy with these configurations. It handles:
|
|
81
|
+
*
|
|
82
|
+
* - Extracting domain, target, and certificate information from routes
|
|
83
|
+
* - Converting TLS mode settings to NetworkProxy configuration
|
|
84
|
+
* - Applying security and advanced settings
|
|
85
|
+
* - Registering domains for ACME certificate provisioning when needed
|
|
86
|
+
*
|
|
87
|
+
* @param routes The route configurations to sync to NetworkProxy
|
|
88
|
+
*/
|
|
89
|
+
syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Map routes directly to NetworkProxy configuration format
|
|
92
|
+
*
|
|
93
|
+
* This method directly maps route configurations to NetworkProxy's format
|
|
94
|
+
* without any intermediate domain-based representation. It processes each route
|
|
95
|
+
* and creates appropriate NetworkProxy configs for domains that require TLS termination.
|
|
96
|
+
*
|
|
97
|
+
* @param routes Array of route configurations to map
|
|
98
|
+
* @param defaultCertPair Default certificate to use if no custom certificate is specified
|
|
99
|
+
* @returns Array of NetworkProxy configurations
|
|
100
|
+
*/
|
|
101
|
+
mapRoutesToNetworkProxyConfigs(routes: IRouteConfig[], defaultCertPair: {
|
|
102
|
+
key: string;
|
|
103
|
+
cert: string;
|
|
104
|
+
}): plugins.tsclass.network.IReverseProxyConfig[];
|
|
105
|
+
/**
|
|
106
|
+
* @deprecated This method is kept for backward compatibility.
|
|
107
|
+
* Use mapRoutesToNetworkProxyConfigs() instead.
|
|
108
|
+
*/
|
|
109
|
+
convertRoutesToNetworkProxyConfigs(routes: IRouteConfig[], defaultCertPair: {
|
|
110
|
+
key: string;
|
|
111
|
+
cert: string;
|
|
112
|
+
}): plugins.tsclass.network.IReverseProxyConfig[];
|
|
113
|
+
/**
|
|
114
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
115
|
+
* Use syncRoutesToNetworkProxy() instead.
|
|
116
|
+
*
|
|
117
|
+
* This legacy method exists only for backward compatibility and
|
|
118
|
+
* simply forwards to syncRoutesToNetworkProxy().
|
|
56
119
|
*/
|
|
57
120
|
syncDomainConfigsToNetworkProxy(): Promise<void>;
|
|
58
121
|
/**
|
|
59
122
|
* Request a certificate for a specific domain
|
|
123
|
+
*
|
|
124
|
+
* @param domain The domain to request a certificate for
|
|
125
|
+
* @param routeName Optional route name to associate with this certificate
|
|
60
126
|
*/
|
|
61
|
-
requestCertificate(domain: string): Promise<boolean>;
|
|
127
|
+
requestCertificate(domain: string, routeName?: string): Promise<boolean>;
|
|
62
128
|
}
|
|
@@ -5,6 +5,14 @@ import { Port80HandlerEvents } from '../../core/models/common-types.js';
|
|
|
5
5
|
import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* Manages NetworkProxy integration for TLS termination
|
|
8
|
+
*
|
|
9
|
+
* NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
|
|
10
|
+
* It directly maps route configurations to NetworkProxy configuration format and manages
|
|
11
|
+
* certificate provisioning through Port80Handler when ACME is enabled.
|
|
12
|
+
*
|
|
13
|
+
* It is used by SmartProxy for routes that have:
|
|
14
|
+
* - TLS mode of 'terminate' or 'terminate-and-reencrypt'
|
|
15
|
+
* - Certificate set to 'auto' or custom certificate
|
|
8
16
|
*/
|
|
9
17
|
export class NetworkProxyBridge {
|
|
10
18
|
constructor(settings) {
|
|
@@ -46,8 +54,8 @@ export class NetworkProxyBridge {
|
|
|
46
54
|
if (this.port80Handler) {
|
|
47
55
|
this.networkProxy.setExternalPort80Handler(this.port80Handler);
|
|
48
56
|
}
|
|
49
|
-
//
|
|
50
|
-
await this.
|
|
57
|
+
// Apply route configurations to NetworkProxy
|
|
58
|
+
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
|
51
59
|
}
|
|
52
60
|
}
|
|
53
61
|
/**
|
|
@@ -128,25 +136,50 @@ export class NetworkProxyBridge {
|
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
138
|
/**
|
|
131
|
-
* Register domains with Port80Handler
|
|
139
|
+
* Register domains from routes with Port80Handler for certificate management
|
|
140
|
+
*
|
|
141
|
+
* Extracts domains from routes that require TLS termination and registers them
|
|
142
|
+
* with the Port80Handler for certificate issuance and renewal.
|
|
143
|
+
*
|
|
144
|
+
* @param routes The route configurations to extract domains from
|
|
132
145
|
*/
|
|
133
|
-
registerDomainsWithPort80Handler(
|
|
146
|
+
registerDomainsWithPort80Handler(routes) {
|
|
134
147
|
if (!this.port80Handler) {
|
|
135
148
|
console.log('Cannot register domains - Port80Handler not initialized');
|
|
136
149
|
return;
|
|
137
150
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
151
|
+
// Extract domains from routes that require TLS termination
|
|
152
|
+
const domainsToRegister = new Set();
|
|
153
|
+
for (const route of routes) {
|
|
154
|
+
// Skip routes without domains or TLS configuration
|
|
155
|
+
if (!route.match.domains || !route.action.tls)
|
|
142
156
|
continue;
|
|
157
|
+
// Only register domains for routes that terminate TLS
|
|
158
|
+
if (route.action.tls.mode !== 'terminate' && route.action.tls.mode !== 'terminate-and-reencrypt')
|
|
159
|
+
continue;
|
|
160
|
+
// Extract domains from route
|
|
161
|
+
const domains = Array.isArray(route.match.domains)
|
|
162
|
+
? route.match.domains
|
|
163
|
+
: [route.match.domains];
|
|
164
|
+
// Add each domain to the set (avoiding duplicates)
|
|
165
|
+
for (const domain of domains) {
|
|
166
|
+
// Skip wildcards
|
|
167
|
+
if (domain.includes('*')) {
|
|
168
|
+
console.log(`Skipping wildcard domain for ACME: ${domain}`);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
domainsToRegister.add(domain);
|
|
143
172
|
}
|
|
144
|
-
|
|
173
|
+
}
|
|
174
|
+
// Register each unique domain with Port80Handler
|
|
175
|
+
for (const domain of domainsToRegister) {
|
|
145
176
|
try {
|
|
146
177
|
this.port80Handler.addDomain({
|
|
147
178
|
domainName: domain,
|
|
148
179
|
sslRedirect: true,
|
|
149
|
-
acmeMaintenance: true
|
|
180
|
+
acmeMaintenance: true,
|
|
181
|
+
// Include route reference if we can find it
|
|
182
|
+
routeReference: this.findRouteReferenceForDomain(domain, routes)
|
|
150
183
|
});
|
|
151
184
|
console.log(`Registered domain with Port80Handler: ${domain}`);
|
|
152
185
|
}
|
|
@@ -155,6 +188,30 @@ export class NetworkProxyBridge {
|
|
|
155
188
|
}
|
|
156
189
|
}
|
|
157
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Finds the route reference for a given domain
|
|
193
|
+
*
|
|
194
|
+
* @param domain The domain to find a route reference for
|
|
195
|
+
* @param routes The routes to search
|
|
196
|
+
* @returns The route reference if found, undefined otherwise
|
|
197
|
+
*/
|
|
198
|
+
findRouteReferenceForDomain(domain, routes) {
|
|
199
|
+
// Find the first route that matches this domain
|
|
200
|
+
for (const route of routes) {
|
|
201
|
+
if (!route.match.domains)
|
|
202
|
+
continue;
|
|
203
|
+
const domains = Array.isArray(route.match.domains)
|
|
204
|
+
? route.match.domains
|
|
205
|
+
: [route.match.domains];
|
|
206
|
+
if (domains.includes(domain)) {
|
|
207
|
+
return {
|
|
208
|
+
routeId: undefined, // No explicit IDs in our current routes
|
|
209
|
+
routeName: route.name
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
158
215
|
/**
|
|
159
216
|
* Forwards a TLS connection to a NetworkProxy for handling
|
|
160
217
|
*/
|
|
@@ -206,9 +263,19 @@ export class NetworkProxyBridge {
|
|
|
206
263
|
});
|
|
207
264
|
}
|
|
208
265
|
/**
|
|
209
|
-
* Synchronizes
|
|
266
|
+
* Synchronizes routes to NetworkProxy
|
|
267
|
+
*
|
|
268
|
+
* This method directly maps route configurations to NetworkProxy format and updates
|
|
269
|
+
* the NetworkProxy with these configurations. It handles:
|
|
270
|
+
*
|
|
271
|
+
* - Extracting domain, target, and certificate information from routes
|
|
272
|
+
* - Converting TLS mode settings to NetworkProxy configuration
|
|
273
|
+
* - Applying security and advanced settings
|
|
274
|
+
* - Registering domains for ACME certificate provisioning when needed
|
|
275
|
+
*
|
|
276
|
+
* @param routes The route configurations to sync to NetworkProxy
|
|
210
277
|
*/
|
|
211
|
-
async
|
|
278
|
+
async syncRoutesToNetworkProxy(routes) {
|
|
212
279
|
if (!this.networkProxy) {
|
|
213
280
|
console.log('Cannot sync configurations - NetworkProxy not initialized');
|
|
214
281
|
return;
|
|
@@ -217,9 +284,9 @@ export class NetworkProxyBridge {
|
|
|
217
284
|
// Get SSL certificates from assets
|
|
218
285
|
// Import fs directly since it's not in plugins
|
|
219
286
|
const fs = await import('fs');
|
|
220
|
-
let
|
|
287
|
+
let defaultCertPair;
|
|
221
288
|
try {
|
|
222
|
-
|
|
289
|
+
defaultCertPair = {
|
|
223
290
|
key: fs.readFileSync('assets/certs/key.pem', 'utf8'),
|
|
224
291
|
cert: fs.readFileSync('assets/certs/cert.pem', 'utf8'),
|
|
225
292
|
};
|
|
@@ -229,42 +296,110 @@ export class NetworkProxyBridge {
|
|
|
229
296
|
console.log('Using empty certificate placeholders - ACME will generate proper certificates if enabled');
|
|
230
297
|
// Use empty placeholders - NetworkProxy will use its internal defaults
|
|
231
298
|
// or ACME will generate proper ones if enabled
|
|
232
|
-
|
|
299
|
+
defaultCertPair = {
|
|
233
300
|
key: '',
|
|
234
301
|
cert: '',
|
|
235
302
|
};
|
|
236
303
|
}
|
|
237
|
-
//
|
|
238
|
-
const proxyConfigs = this.
|
|
239
|
-
//
|
|
240
|
-
const acmeEnabled = !!this.settings.acme?.enabled;
|
|
241
|
-
if (acmeEnabled) {
|
|
242
|
-
const acmeEligibleDomains = proxyConfigs
|
|
243
|
-
.filter((config) => !config.hostName.includes('*')) // Exclude wildcards
|
|
244
|
-
.map((config) => config.hostName);
|
|
245
|
-
if (acmeEligibleDomains.length > 0) {
|
|
246
|
-
console.log(`Domains eligible for ACME certificates: ${acmeEligibleDomains.join(', ')}`);
|
|
247
|
-
// Register these domains with Port80Handler if available
|
|
248
|
-
if (this.port80Handler) {
|
|
249
|
-
this.registerDomainsWithPort80Handler(acmeEligibleDomains);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
console.log('No domains eligible for ACME certificates found in configuration');
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
// Update NetworkProxy with the converted configs
|
|
304
|
+
// Map routes directly to NetworkProxy configs
|
|
305
|
+
const proxyConfigs = this.mapRoutesToNetworkProxyConfigs(routes, defaultCertPair);
|
|
306
|
+
// Update the proxy configs
|
|
257
307
|
await this.networkProxy.updateProxyConfigs(proxyConfigs);
|
|
258
|
-
console.log(`
|
|
308
|
+
console.log(`Synced ${proxyConfigs.length} configurations to NetworkProxy`);
|
|
309
|
+
// Register domains with Port80Handler for certificate issuance
|
|
310
|
+
if (this.port80Handler) {
|
|
311
|
+
this.registerDomainsWithPort80Handler(routes);
|
|
312
|
+
}
|
|
259
313
|
}
|
|
260
314
|
catch (err) {
|
|
261
|
-
console.log(`
|
|
315
|
+
console.log(`Error syncing routes to NetworkProxy: ${err}`);
|
|
262
316
|
}
|
|
263
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Map routes directly to NetworkProxy configuration format
|
|
320
|
+
*
|
|
321
|
+
* This method directly maps route configurations to NetworkProxy's format
|
|
322
|
+
* without any intermediate domain-based representation. It processes each route
|
|
323
|
+
* and creates appropriate NetworkProxy configs for domains that require TLS termination.
|
|
324
|
+
*
|
|
325
|
+
* @param routes Array of route configurations to map
|
|
326
|
+
* @param defaultCertPair Default certificate to use if no custom certificate is specified
|
|
327
|
+
* @returns Array of NetworkProxy configurations
|
|
328
|
+
*/
|
|
329
|
+
mapRoutesToNetworkProxyConfigs(routes, defaultCertPair) {
|
|
330
|
+
const configs = [];
|
|
331
|
+
for (const route of routes) {
|
|
332
|
+
// Skip routes without domains
|
|
333
|
+
if (!route.match.domains)
|
|
334
|
+
continue;
|
|
335
|
+
// Skip non-forward routes
|
|
336
|
+
if (route.action.type !== 'forward')
|
|
337
|
+
continue;
|
|
338
|
+
// Skip routes without TLS configuration
|
|
339
|
+
if (!route.action.tls || !route.action.target)
|
|
340
|
+
continue;
|
|
341
|
+
// Skip routes that don't require TLS termination
|
|
342
|
+
if (route.action.tls.mode !== 'terminate' && route.action.tls.mode !== 'terminate-and-reencrypt')
|
|
343
|
+
continue;
|
|
344
|
+
// Get domains from route
|
|
345
|
+
const domains = Array.isArray(route.match.domains)
|
|
346
|
+
? route.match.domains
|
|
347
|
+
: [route.match.domains];
|
|
348
|
+
// Create a config for each domain
|
|
349
|
+
for (const domain of domains) {
|
|
350
|
+
// Get certificate
|
|
351
|
+
let certKey = defaultCertPair.key;
|
|
352
|
+
let certCert = defaultCertPair.cert;
|
|
353
|
+
// Use custom certificate if specified
|
|
354
|
+
if (route.action.tls.certificate !== 'auto' && typeof route.action.tls.certificate === 'object') {
|
|
355
|
+
certKey = route.action.tls.certificate.key;
|
|
356
|
+
certCert = route.action.tls.certificate.cert;
|
|
357
|
+
}
|
|
358
|
+
// Determine target hosts and ports
|
|
359
|
+
const targetHosts = Array.isArray(route.action.target.host)
|
|
360
|
+
? route.action.target.host
|
|
361
|
+
: [route.action.target.host];
|
|
362
|
+
const targetPort = route.action.target.port;
|
|
363
|
+
// Create the NetworkProxy config
|
|
364
|
+
const config = {
|
|
365
|
+
hostName: domain,
|
|
366
|
+
privateKey: certKey,
|
|
367
|
+
publicKey: certCert,
|
|
368
|
+
destinationIps: targetHosts,
|
|
369
|
+
destinationPorts: [targetPort]
|
|
370
|
+
// Note: We can't include additional metadata as it's not supported in the interface
|
|
371
|
+
};
|
|
372
|
+
configs.push(config);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return configs;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* @deprecated This method is kept for backward compatibility.
|
|
379
|
+
* Use mapRoutesToNetworkProxyConfigs() instead.
|
|
380
|
+
*/
|
|
381
|
+
convertRoutesToNetworkProxyConfigs(routes, defaultCertPair) {
|
|
382
|
+
return this.mapRoutesToNetworkProxyConfigs(routes, defaultCertPair);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* @deprecated This method is deprecated and will be removed in a future version.
|
|
386
|
+
* Use syncRoutesToNetworkProxy() instead.
|
|
387
|
+
*
|
|
388
|
+
* This legacy method exists only for backward compatibility and
|
|
389
|
+
* simply forwards to syncRoutesToNetworkProxy().
|
|
390
|
+
*/
|
|
391
|
+
async syncDomainConfigsToNetworkProxy() {
|
|
392
|
+
console.log('DEPRECATED: Method syncDomainConfigsToNetworkProxy will be removed in a future version.');
|
|
393
|
+
console.log('Please use syncRoutesToNetworkProxy() instead for direct route-based configuration.');
|
|
394
|
+
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
|
395
|
+
}
|
|
264
396
|
/**
|
|
265
397
|
* Request a certificate for a specific domain
|
|
398
|
+
*
|
|
399
|
+
* @param domain The domain to request a certificate for
|
|
400
|
+
* @param routeName Optional route name to associate with this certificate
|
|
266
401
|
*/
|
|
267
|
-
async requestCertificate(domain) {
|
|
402
|
+
async requestCertificate(domain, routeName) {
|
|
268
403
|
// Delegate to Port80Handler if available
|
|
269
404
|
if (this.port80Handler) {
|
|
270
405
|
try {
|
|
@@ -274,12 +409,27 @@ export class NetworkProxyBridge {
|
|
|
274
409
|
console.log(`Certificate already exists for ${domain}`);
|
|
275
410
|
return true;
|
|
276
411
|
}
|
|
277
|
-
//
|
|
278
|
-
|
|
412
|
+
// Build the domain options
|
|
413
|
+
const domainOptions = {
|
|
279
414
|
domainName: domain,
|
|
280
415
|
sslRedirect: true,
|
|
281
|
-
acmeMaintenance: true
|
|
282
|
-
}
|
|
416
|
+
acmeMaintenance: true,
|
|
417
|
+
};
|
|
418
|
+
// Add route reference if available
|
|
419
|
+
if (routeName) {
|
|
420
|
+
domainOptions.routeReference = {
|
|
421
|
+
routeName
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
// Try to find a route reference from the current routes
|
|
426
|
+
const routeReference = this.findRouteReferenceForDomain(domain, this.settings.routes || []);
|
|
427
|
+
if (routeReference) {
|
|
428
|
+
domainOptions.routeReference = routeReference;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// Register the domain for certificate issuance
|
|
432
|
+
this.port80Handler.addDomain(domainOptions);
|
|
283
433
|
console.log(`Domain ${domain} registered for certificate issuance`);
|
|
284
434
|
return true;
|
|
285
435
|
}
|
|
@@ -313,4 +463,4 @@ export class NetworkProxyBridge {
|
|
|
313
463
|
}
|
|
314
464
|
}
|
|
315
465
|
}
|
|
316
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29yay1wcm94eS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L25ldHdvcmstcHJveHktYnJpZGdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUkzRTs7R0FFRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFJN0IsWUFBb0IsUUFBNEI7UUFBNUIsYUFBUSxHQUFSLFFBQVEsQ0FBb0I7UUFIeEMsaUJBQVksR0FBd0IsSUFBSSxDQUFDO1FBQ3pDLGtCQUFhLEdBQXlCLElBQUksQ0FBQztJQUVBLENBQUM7SUFFcEQ7O09BRUc7SUFDSSxnQkFBZ0IsQ0FBQyxPQUFzQjtRQUM1QyxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQztRQUU3QixrQ0FBa0M7UUFDbEMsd0JBQXdCLENBQUMsT0FBTyxFQUFFO1lBQ2hDLG1CQUFtQixFQUFFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBQzNELG9CQUFvQixFQUFFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1NBQzdELENBQUMsQ0FBQztRQUVILHdFQUF3RTtRQUN4RSxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN0QixJQUFJLENBQUMsWUFBWSxDQUFDLHdCQUF3QixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RELENBQUM7UUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLCtD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
|
|
466
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29yay1wcm94eS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L25ldHdvcmstcHJveHktYnJpZGdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUszRTs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxPQUFPLGtCQUFrQjtJQUk3QixZQUFvQixRQUE0QjtRQUE1QixhQUFRLEdBQVIsUUFBUSxDQUFvQjtRQUh4QyxpQkFBWSxHQUF3QixJQUFJLENBQUM7UUFDekMsa0JBQWEsR0FBeUIsSUFBSSxDQUFDO0lBRUEsQ0FBQztJQUVwRDs7T0FFRztJQUNJLGdCQUFnQixDQUFDLE9BQXNCO1FBQzVDLElBQUksQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDO1FBRTdCLGtDQUFrQztRQUNsQyx3QkFBd0IsQ0FBQyxPQUFPLEVBQUU7WUFDaEMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDM0Qsb0JBQW9CLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7U0FDN0QsQ0FBQyxDQUFDO1FBRUgsd0VBQXdFO1FBQ3hFLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxZQUFZLENBQUMsd0JBQXdCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEQsQ0FBQztRQUVELE9BQU8sQ0FBQyxHQUFH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
|