@push.rocks/smartproxy 18.0.2 → 18.2.0
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/certificate-manager.d.ts +150 -0
- package/dist_ts/certificate/certificate-manager.js +505 -0
- package/dist_ts/certificate/events/simplified-events.d.ts +56 -0
- package/dist_ts/certificate/events/simplified-events.js +13 -0
- package/dist_ts/certificate/models/certificate-errors.d.ts +69 -0
- package/dist_ts/certificate/models/certificate-errors.js +141 -0
- package/dist_ts/certificate/models/certificate-strategy.d.ts +60 -0
- package/dist_ts/certificate/models/certificate-strategy.js +73 -0
- package/dist_ts/certificate/simplified-certificate-manager.d.ts +150 -0
- package/dist_ts/certificate/simplified-certificate-manager.js +501 -0
- package/dist_ts/http/index.d.ts +1 -9
- package/dist_ts/http/index.js +5 -11
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +4 -2
- package/dist_ts/proxies/network-proxy/network-proxy.js +3 -1
- package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.d.ts +48 -0
- package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.js +76 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.js +41 -4
- package/dist_ts/proxies/smart-proxy/cert-store.d.ts +10 -0
- package/dist_ts/proxies/smart-proxy/cert-store.js +70 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +116 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +401 -0
- package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.d.ts +168 -0
- package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.js +642 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +26 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.d.ts +65 -0
- package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.js +31 -0
- package/dist_ts/proxies/smart-proxy/models/smartproxy-options.d.ts +102 -0
- package/dist_ts/proxies/smart-proxy/models/smartproxy-options.js +73 -0
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +10 -44
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +66 -202
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +62 -2
- package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.d.ts +41 -0
- package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.js +132 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +18 -13
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +79 -196
- package/package.json +7 -5
- package/readme.md +224 -10
- package/readme.plan.md +1405 -617
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/http/index.ts +5 -12
- package/ts/plugins.ts +4 -1
- package/ts/proxies/network-proxy/network-proxy.ts +3 -0
- package/ts/proxies/network-proxy/websocket-handler.ts +38 -3
- package/ts/proxies/smart-proxy/cert-store.ts +86 -0
- package/ts/proxies/smart-proxy/certificate-manager.ts +506 -0
- package/ts/proxies/smart-proxy/models/route-types.ts +33 -3
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +86 -239
- package/ts/proxies/smart-proxy/route-connection-handler.ts +74 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +105 -222
|
@@ -1,46 +1,18 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import { NetworkProxy } from '../network-proxy/index.js';
|
|
3
|
-
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
4
|
-
import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
|
|
5
|
-
import type { ICertificateData } from '../../certificate/models/certificate-types.js';
|
|
6
3
|
import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
|
|
7
4
|
import type { IRouteConfig } from './models/route-types.js';
|
|
8
5
|
|
|
9
|
-
/**
|
|
10
|
-
* Manages NetworkProxy integration for TLS termination
|
|
11
|
-
*
|
|
12
|
-
* NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
|
|
13
|
-
* It directly passes route configurations to NetworkProxy and manages the physical
|
|
14
|
-
* connection piping between SmartProxy and NetworkProxy for TLS termination.
|
|
15
|
-
*
|
|
16
|
-
* It is used by SmartProxy for routes that have:
|
|
17
|
-
* - TLS mode of 'terminate' or 'terminate-and-reencrypt'
|
|
18
|
-
* - Certificate set to 'auto' or custom certificate
|
|
19
|
-
*/
|
|
20
6
|
export class NetworkProxyBridge {
|
|
21
7
|
private networkProxy: NetworkProxy | null = null;
|
|
22
|
-
private port80Handler: Port80Handler | null = null;
|
|
23
8
|
|
|
24
9
|
constructor(private settings: ISmartProxyOptions) {}
|
|
25
10
|
|
|
26
11
|
/**
|
|
27
|
-
*
|
|
12
|
+
* Get the NetworkProxy instance
|
|
28
13
|
*/
|
|
29
|
-
public
|
|
30
|
-
this.
|
|
31
|
-
|
|
32
|
-
// Subscribe to certificate events
|
|
33
|
-
subscribeToPort80Handler(handler, {
|
|
34
|
-
onCertificateIssued: this.handleCertificateEvent.bind(this),
|
|
35
|
-
onCertificateRenewed: this.handleCertificateEvent.bind(this)
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// If NetworkProxy is already initialized, connect it with Port80Handler
|
|
39
|
-
if (this.networkProxy) {
|
|
40
|
-
this.networkProxy.setExternalPort80Handler(handler);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log('Port80Handler connected to NetworkProxyBridge');
|
|
14
|
+
public getNetworkProxy(): NetworkProxy | null {
|
|
15
|
+
return this.networkProxy;
|
|
44
16
|
}
|
|
45
17
|
|
|
46
18
|
/**
|
|
@@ -48,22 +20,14 @@ export class NetworkProxyBridge {
|
|
|
48
20
|
*/
|
|
49
21
|
public async initialize(): Promise<void> {
|
|
50
22
|
if (!this.networkProxy && this.settings.useNetworkProxy && this.settings.useNetworkProxy.length > 0) {
|
|
51
|
-
// Configure NetworkProxy options based on SmartProxy settings
|
|
52
23
|
const networkProxyOptions: any = {
|
|
53
24
|
port: this.settings.networkProxyPort!,
|
|
54
25
|
portProxyIntegration: true,
|
|
55
|
-
logLevel: this.settings.enableDetailedLogging ? 'debug' : 'info'
|
|
56
|
-
useExternalPort80Handler: !!this.port80Handler // Use Port80Handler if available
|
|
26
|
+
logLevel: this.settings.enableDetailedLogging ? 'debug' : 'info'
|
|
57
27
|
};
|
|
58
28
|
|
|
59
29
|
this.networkProxy = new NetworkProxy(networkProxyOptions);
|
|
60
|
-
|
|
61
30
|
console.log(`Initialized NetworkProxy on port ${this.settings.networkProxyPort}`);
|
|
62
|
-
|
|
63
|
-
// Connect Port80Handler if available
|
|
64
|
-
if (this.port80Handler) {
|
|
65
|
-
this.networkProxy.setExternalPort80Handler(this.port80Handler);
|
|
66
|
-
}
|
|
67
31
|
|
|
68
32
|
// Apply route configurations to NetworkProxy
|
|
69
33
|
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
|
@@ -71,235 +35,118 @@ export class NetworkProxyBridge {
|
|
|
71
35
|
}
|
|
72
36
|
|
|
73
37
|
/**
|
|
74
|
-
*
|
|
38
|
+
* Sync routes to NetworkProxy
|
|
75
39
|
*/
|
|
76
|
-
|
|
40
|
+
public async syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise<void> {
|
|
77
41
|
if (!this.networkProxy) return;
|
|
78
|
-
|
|
79
|
-
console.log(`Received certificate for ${data.domain} from Port80Handler, updating NetworkProxy`);
|
|
80
|
-
|
|
81
|
-
// Apply certificate directly to NetworkProxy
|
|
82
|
-
this.networkProxy.updateCertificate(data.domain, data.certificate, data.privateKey);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Apply an external (static) certificate into NetworkProxy
|
|
87
|
-
*/
|
|
88
|
-
public applyExternalCertificate(data: ICertificateData): void {
|
|
89
|
-
if (!this.networkProxy) {
|
|
90
|
-
console.log(`NetworkProxy not initialized: cannot apply external certificate for ${data.domain}`);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
42
|
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
43
|
+
// Convert routes to NetworkProxy format
|
|
44
|
+
const networkProxyConfigs = routes
|
|
45
|
+
.filter(route => {
|
|
46
|
+
// Check if this route matches any of the specified network proxy ports
|
|
47
|
+
const routePorts = Array.isArray(route.match.ports)
|
|
48
|
+
? route.match.ports
|
|
49
|
+
: [route.match.ports];
|
|
50
|
+
|
|
51
|
+
return routePorts.some(port =>
|
|
52
|
+
this.settings.useNetworkProxy?.includes(port)
|
|
53
|
+
);
|
|
54
|
+
})
|
|
55
|
+
.map(route => this.routeToNetworkProxyConfig(route));
|
|
56
|
+
|
|
57
|
+
// Apply configurations to NetworkProxy
|
|
58
|
+
await this.networkProxy.updateRouteConfigs(networkProxyConfigs);
|
|
110
59
|
}
|
|
111
60
|
|
|
112
61
|
/**
|
|
113
|
-
*
|
|
62
|
+
* Convert route to NetworkProxy configuration
|
|
114
63
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
64
|
+
private routeToNetworkProxyConfig(route: IRouteConfig): any {
|
|
65
|
+
// Convert route to NetworkProxy domain config format
|
|
66
|
+
return {
|
|
67
|
+
domain: route.match.domains?.[0] || '*',
|
|
68
|
+
target: route.action.target,
|
|
69
|
+
tls: route.action.tls,
|
|
70
|
+
security: route.action.security
|
|
71
|
+
};
|
|
120
72
|
}
|
|
121
73
|
|
|
122
74
|
/**
|
|
123
|
-
*
|
|
75
|
+
* Check if connection should use NetworkProxy
|
|
124
76
|
*/
|
|
125
|
-
public
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
} catch (err) {
|
|
132
|
-
console.log(`Error stopping NetworkProxy: ${err}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
77
|
+
public shouldUseNetworkProxy(connection: IConnectionRecord, routeMatch: any): boolean {
|
|
78
|
+
// Only use NetworkProxy for TLS termination
|
|
79
|
+
return (
|
|
80
|
+
routeMatch.route.action.tls?.mode === 'terminate' ||
|
|
81
|
+
routeMatch.route.action.tls?.mode === 'terminate-and-reencrypt'
|
|
82
|
+
) && this.networkProxy !== null;
|
|
135
83
|
}
|
|
136
84
|
|
|
137
85
|
/**
|
|
138
|
-
*
|
|
86
|
+
* Forward connection to NetworkProxy
|
|
139
87
|
*/
|
|
140
|
-
public forwardToNetworkProxy(
|
|
88
|
+
public async forwardToNetworkProxy(
|
|
141
89
|
connectionId: string,
|
|
142
90
|
socket: plugins.net.Socket,
|
|
143
91
|
record: IConnectionRecord,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
): void {
|
|
148
|
-
// Ensure NetworkProxy is initialized
|
|
92
|
+
initialChunk: Buffer,
|
|
93
|
+
networkProxyPort: number,
|
|
94
|
+
cleanupCallback: (reason: string) => void
|
|
95
|
+
): Promise<void> {
|
|
149
96
|
if (!this.networkProxy) {
|
|
150
|
-
|
|
151
|
-
`[${connectionId}] NetworkProxy not initialized. Cannot forward connection.`
|
|
152
|
-
);
|
|
153
|
-
if (onError) {
|
|
154
|
-
onError('network_proxy_not_initialized');
|
|
155
|
-
}
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Use the custom port if provided, otherwise use the default NetworkProxy port
|
|
160
|
-
const proxyPort = customProxyPort || this.networkProxy.getListeningPort();
|
|
161
|
-
const proxyHost = 'localhost'; // Assuming NetworkProxy runs locally
|
|
162
|
-
|
|
163
|
-
if (this.settings.enableDetailedLogging) {
|
|
164
|
-
console.log(
|
|
165
|
-
`[${connectionId}] Forwarding TLS connection to NetworkProxy at ${proxyHost}:${proxyPort}`
|
|
166
|
-
);
|
|
97
|
+
throw new Error('NetworkProxy not initialized');
|
|
167
98
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
record.usingNetworkProxy = true;
|
|
179
|
-
|
|
180
|
-
// Set up error handlers
|
|
181
|
-
proxySocket.on('error', (err) => {
|
|
182
|
-
console.log(`[${connectionId}] Error connecting to NetworkProxy: ${err.message}`);
|
|
183
|
-
if (onError) {
|
|
184
|
-
onError('network_proxy_connect_error');
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// Handle connection to NetworkProxy
|
|
189
|
-
proxySocket.on('connect', () => {
|
|
190
|
-
if (this.settings.enableDetailedLogging) {
|
|
191
|
-
console.log(`[${connectionId}] Connected to NetworkProxy at ${proxyHost}:${proxyPort}`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// First send the initial data that contains the TLS ClientHello
|
|
195
|
-
proxySocket.write(initialData);
|
|
196
|
-
|
|
197
|
-
// Now set up bidirectional piping between client and NetworkProxy
|
|
198
|
-
socket.pipe(proxySocket);
|
|
199
|
-
proxySocket.pipe(socket);
|
|
200
|
-
|
|
201
|
-
if (this.settings.enableDetailedLogging) {
|
|
202
|
-
console.log(`[${connectionId}] TLS connection successfully forwarded to NetworkProxy`);
|
|
203
|
-
}
|
|
99
|
+
|
|
100
|
+
const proxySocket = new plugins.net.Socket();
|
|
101
|
+
|
|
102
|
+
await new Promise<void>((resolve, reject) => {
|
|
103
|
+
proxySocket.connect(networkProxyPort, 'localhost', () => {
|
|
104
|
+
console.log(`[${connectionId}] Connected to NetworkProxy for termination`);
|
|
105
|
+
resolve();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
proxySocket.on('error', reject);
|
|
204
109
|
});
|
|
110
|
+
|
|
111
|
+
// Send initial chunk if present
|
|
112
|
+
if (initialChunk) {
|
|
113
|
+
proxySocket.write(initialChunk);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Pipe the sockets together
|
|
117
|
+
socket.pipe(proxySocket);
|
|
118
|
+
proxySocket.pipe(socket);
|
|
119
|
+
|
|
120
|
+
// Handle cleanup
|
|
121
|
+
const cleanup = (reason: string) => {
|
|
122
|
+
socket.unpipe(proxySocket);
|
|
123
|
+
proxySocket.unpipe(socket);
|
|
124
|
+
proxySocket.destroy();
|
|
125
|
+
cleanupCallback(reason);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
socket.on('end', () => cleanup('socket_end'));
|
|
129
|
+
socket.on('error', () => cleanup('socket_error'));
|
|
130
|
+
proxySocket.on('end', () => cleanup('proxy_end'));
|
|
131
|
+
proxySocket.on('error', () => cleanup('proxy_error'));
|
|
205
132
|
}
|
|
206
133
|
|
|
207
134
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* This method directly passes route configurations to NetworkProxy without any
|
|
211
|
-
* intermediate conversion. NetworkProxy natively understands route configurations.
|
|
212
|
-
*
|
|
213
|
-
* @param routes The route configurations to sync to NetworkProxy
|
|
135
|
+
* Start NetworkProxy
|
|
214
136
|
*/
|
|
215
|
-
public async
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
// Filter only routes that are applicable to NetworkProxy (TLS termination)
|
|
223
|
-
const networkProxyRoutes = routes.filter(route => {
|
|
224
|
-
return (
|
|
225
|
-
route.action.type === 'forward' &&
|
|
226
|
-
route.action.tls &&
|
|
227
|
-
(route.action.tls.mode === 'terminate' || route.action.tls.mode === 'terminate-and-reencrypt')
|
|
228
|
-
);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
// Pass routes directly to NetworkProxy
|
|
232
|
-
await this.networkProxy.updateRouteConfigs(networkProxyRoutes);
|
|
233
|
-
console.log(`Synced ${networkProxyRoutes.length} routes directly to NetworkProxy`);
|
|
234
|
-
} catch (err) {
|
|
235
|
-
console.log(`Error syncing routes to NetworkProxy: ${err}`);
|
|
137
|
+
public async start(): Promise<void> {
|
|
138
|
+
if (this.networkProxy) {
|
|
139
|
+
await this.networkProxy.start();
|
|
236
140
|
}
|
|
237
141
|
}
|
|
238
142
|
|
|
239
143
|
/**
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* @param domain The domain to request a certificate for
|
|
243
|
-
* @param routeName Optional route name to associate with this certificate
|
|
144
|
+
* Stop NetworkProxy
|
|
244
145
|
*/
|
|
245
|
-
public async
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// Check if the domain is already registered
|
|
250
|
-
const cert = this.port80Handler.getCertificate(domain);
|
|
251
|
-
if (cert) {
|
|
252
|
-
console.log(`Certificate already exists for ${domain}`);
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Build the domain options
|
|
257
|
-
const domainOptions: any = {
|
|
258
|
-
domainName: domain,
|
|
259
|
-
sslRedirect: true,
|
|
260
|
-
acmeMaintenance: true,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
// Add route reference if available
|
|
264
|
-
if (routeName) {
|
|
265
|
-
domainOptions.routeReference = {
|
|
266
|
-
routeName
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Register the domain for certificate issuance
|
|
271
|
-
this.port80Handler.addDomain(domainOptions);
|
|
272
|
-
|
|
273
|
-
console.log(`Domain ${domain} registered for certificate issuance`);
|
|
274
|
-
return true;
|
|
275
|
-
} catch (err) {
|
|
276
|
-
console.log(`Error requesting certificate: ${err}`);
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Fall back to NetworkProxy if Port80Handler is not available
|
|
282
|
-
if (!this.networkProxy) {
|
|
283
|
-
console.log('Cannot request certificate - NetworkProxy not initialized');
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (!this.settings.acme?.enabled) {
|
|
288
|
-
console.log('Cannot request certificate - ACME is not enabled');
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
const result = await this.networkProxy.requestCertificate(domain);
|
|
294
|
-
if (result) {
|
|
295
|
-
console.log(`Certificate request for ${domain} submitted successfully`);
|
|
296
|
-
} else {
|
|
297
|
-
console.log(`Certificate request for ${domain} failed`);
|
|
298
|
-
}
|
|
299
|
-
return result;
|
|
300
|
-
} catch (err) {
|
|
301
|
-
console.log(`Error requesting certificate: ${err}`);
|
|
302
|
-
return false;
|
|
146
|
+
public async stop(): Promise<void> {
|
|
147
|
+
if (this.networkProxy) {
|
|
148
|
+
await this.networkProxy.stop();
|
|
149
|
+
this.networkProxy = null;
|
|
303
150
|
}
|
|
304
151
|
}
|
|
305
152
|
}
|
|
@@ -365,6 +365,10 @@ export class RouteConnectionHandler {
|
|
|
365
365
|
case 'block':
|
|
366
366
|
return this.handleBlockAction(socket, record, route);
|
|
367
367
|
|
|
368
|
+
case 'static':
|
|
369
|
+
this.handleStaticAction(socket, record, route);
|
|
370
|
+
return;
|
|
371
|
+
|
|
368
372
|
default:
|
|
369
373
|
console.log(`[${connectionId}] Unknown action type: ${(route.action as any).type}`);
|
|
370
374
|
socket.end();
|
|
@@ -528,7 +532,7 @@ export class RouteConnectionHandler {
|
|
|
528
532
|
|
|
529
533
|
// If we have an initial chunk with TLS data, start processing it
|
|
530
534
|
if (initialChunk && record.isTLS) {
|
|
531
|
-
|
|
535
|
+
this.networkProxyBridge.forwardToNetworkProxy(
|
|
532
536
|
connectionId,
|
|
533
537
|
socket,
|
|
534
538
|
record,
|
|
@@ -536,6 +540,7 @@ export class RouteConnectionHandler {
|
|
|
536
540
|
this.settings.networkProxyPort,
|
|
537
541
|
(reason) => this.connectionManager.initiateCleanupOnce(record, reason)
|
|
538
542
|
);
|
|
543
|
+
return;
|
|
539
544
|
}
|
|
540
545
|
|
|
541
546
|
// This shouldn't normally happen - we should have TLS data at this point
|
|
@@ -706,6 +711,64 @@ export class RouteConnectionHandler {
|
|
|
706
711
|
this.connectionManager.initiateCleanupOnce(record, 'route_blocked');
|
|
707
712
|
}
|
|
708
713
|
|
|
714
|
+
/**
|
|
715
|
+
* Handle a static action for a route
|
|
716
|
+
*/
|
|
717
|
+
private async handleStaticAction(
|
|
718
|
+
socket: plugins.net.Socket,
|
|
719
|
+
record: IConnectionRecord,
|
|
720
|
+
route: IRouteConfig
|
|
721
|
+
): Promise<void> {
|
|
722
|
+
const connectionId = record.id;
|
|
723
|
+
|
|
724
|
+
if (!route.action.handler) {
|
|
725
|
+
console.error(`[${connectionId}] Static route '${route.name}' has no handler`);
|
|
726
|
+
socket.end();
|
|
727
|
+
this.connectionManager.cleanupConnection(record, 'no_handler');
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
try {
|
|
732
|
+
// Build route context
|
|
733
|
+
const context: IRouteContext = {
|
|
734
|
+
port: record.localPort,
|
|
735
|
+
domain: record.lockedDomain,
|
|
736
|
+
clientIp: record.remoteIP,
|
|
737
|
+
serverIp: socket.localAddress!,
|
|
738
|
+
path: undefined, // Will need to be extracted from HTTP request
|
|
739
|
+
isTls: record.isTLS,
|
|
740
|
+
tlsVersion: record.tlsVersion,
|
|
741
|
+
routeName: route.name,
|
|
742
|
+
routeId: route.name,
|
|
743
|
+
timestamp: Date.now(),
|
|
744
|
+
connectionId
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
// Call the handler
|
|
748
|
+
const response = await route.action.handler(context);
|
|
749
|
+
|
|
750
|
+
// Send HTTP response
|
|
751
|
+
const headers = response.headers || {};
|
|
752
|
+
headers['Content-Length'] = Buffer.byteLength(response.body).toString();
|
|
753
|
+
|
|
754
|
+
let httpResponse = `HTTP/1.1 ${response.status} ${getStatusText(response.status)}\r\n`;
|
|
755
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
756
|
+
httpResponse += `${key}: ${value}\r\n`;
|
|
757
|
+
}
|
|
758
|
+
httpResponse += '\r\n';
|
|
759
|
+
|
|
760
|
+
socket.write(httpResponse);
|
|
761
|
+
socket.write(response.body);
|
|
762
|
+
socket.end();
|
|
763
|
+
|
|
764
|
+
this.connectionManager.cleanupConnection(record, 'completed');
|
|
765
|
+
} catch (error) {
|
|
766
|
+
console.error(`[${connectionId}] Error in static handler: ${error}`);
|
|
767
|
+
socket.end();
|
|
768
|
+
this.connectionManager.cleanupConnection(record, 'handler_error');
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
709
772
|
/**
|
|
710
773
|
* Sets up a direct connection to the target
|
|
711
774
|
*/
|
|
@@ -1131,4 +1194,14 @@ export class RouteConnectionHandler {
|
|
|
1131
1194
|
}
|
|
1132
1195
|
});
|
|
1133
1196
|
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// Helper function for status text
|
|
1200
|
+
function getStatusText(status: number): string {
|
|
1201
|
+
const statusTexts: Record<number, string> = {
|
|
1202
|
+
200: 'OK',
|
|
1203
|
+
404: 'Not Found',
|
|
1204
|
+
500: 'Internal Server Error'
|
|
1205
|
+
};
|
|
1206
|
+
return statusTexts[status] || 'Unknown';
|
|
1134
1207
|
}
|