@push.rocks/smartproxy 25.17.10 → 26.0.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/changelog.md +8 -0
- package/dist_rust/rustproxy_linux_amd64 +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/core/index.d.ts +0 -1
- package/dist_ts/core/index.js +1 -2
- package/dist_ts/core/models/index.d.ts +0 -1
- package/dist_ts/core/models/index.js +1 -2
- package/dist_ts/core/utils/index.d.ts +0 -12
- package/dist_ts/core/utils/index.js +1 -13
- package/dist_ts/index.d.ts +0 -3
- package/dist_ts/index.js +2 -7
- package/dist_ts/protocols/http/index.d.ts +0 -1
- package/dist_ts/protocols/http/index.js +1 -2
- package/dist_ts/protocols/index.d.ts +0 -7
- package/dist_ts/protocols/index.js +1 -8
- package/dist_ts/proxies/smart-proxy/socket-handler-server.js +6 -1
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +0 -7
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +50 -51
- package/dist_ts/routing/index.d.ts +0 -1
- package/dist_ts/routing/index.js +1 -3
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/index.ts +0 -1
- package/ts/core/models/index.ts +0 -1
- package/ts/core/utils/index.ts +0 -12
- package/ts/index.ts +1 -7
- package/ts/protocols/http/index.ts +1 -2
- package/ts/protocols/index.ts +0 -7
- package/ts/proxies/smart-proxy/socket-handler-server.ts +6 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +60 -59
- package/ts/routing/index.ts +0 -3
- package/dist_ts/core/events/index.d.ts +0 -4
- package/dist_ts/core/events/index.js +0 -5
- package/dist_ts/core/models/socket-augmentation.d.ts +0 -15
- package/dist_ts/core/models/socket-augmentation.js +0 -18
- package/dist_ts/core/utils/async-utils.d.ts +0 -81
- package/dist_ts/core/utils/async-utils.js +0 -216
- package/dist_ts/core/utils/binary-heap.d.ts +0 -73
- package/dist_ts/core/utils/binary-heap.js +0 -193
- package/dist_ts/core/utils/enhanced-connection-pool.d.ts +0 -110
- package/dist_ts/core/utils/enhanced-connection-pool.js +0 -325
- package/dist_ts/core/utils/fs-utils.d.ts +0 -144
- package/dist_ts/core/utils/fs-utils.js +0 -252
- package/dist_ts/core/utils/ip-utils.d.ts +0 -69
- package/dist_ts/core/utils/ip-utils.js +0 -270
- package/dist_ts/core/utils/lifecycle-component.d.ts +0 -59
- package/dist_ts/core/utils/lifecycle-component.js +0 -211
- package/dist_ts/core/utils/log-deduplicator.d.ts +0 -39
- package/dist_ts/core/utils/log-deduplicator.js +0 -305
- package/dist_ts/core/utils/security-utils.d.ts +0 -111
- package/dist_ts/core/utils/security-utils.js +0 -212
- package/dist_ts/core/utils/shared-security-manager.d.ts +0 -128
- package/dist_ts/core/utils/shared-security-manager.js +0 -362
- package/dist_ts/core/utils/socket-utils.d.ts +0 -63
- package/dist_ts/core/utils/socket-utils.js +0 -249
- package/dist_ts/core/utils/template-utils.d.ts +0 -37
- package/dist_ts/core/utils/template-utils.js +0 -104
- package/dist_ts/core/utils/validation-utils.d.ts +0 -61
- package/dist_ts/core/utils/validation-utils.js +0 -149
- package/dist_ts/core/utils/websocket-utils.d.ts +0 -22
- package/dist_ts/core/utils/websocket-utils.js +0 -30
- package/dist_ts/detection/detectors/http-detector.d.ts +0 -33
- package/dist_ts/detection/detectors/http-detector.js +0 -101
- package/dist_ts/detection/detectors/quick-detector.d.ts +0 -28
- package/dist_ts/detection/detectors/quick-detector.js +0 -131
- package/dist_ts/detection/detectors/routing-extractor.d.ts +0 -28
- package/dist_ts/detection/detectors/routing-extractor.js +0 -122
- package/dist_ts/detection/detectors/tls-detector.d.ts +0 -47
- package/dist_ts/detection/detectors/tls-detector.js +0 -183
- package/dist_ts/detection/index.d.ts +0 -17
- package/dist_ts/detection/index.js +0 -22
- package/dist_ts/detection/models/detection-types.d.ts +0 -87
- package/dist_ts/detection/models/detection-types.js +0 -5
- package/dist_ts/detection/models/interfaces.d.ts +0 -97
- package/dist_ts/detection/models/interfaces.js +0 -5
- package/dist_ts/detection/protocol-detector.d.ts +0 -79
- package/dist_ts/detection/protocol-detector.js +0 -253
- package/dist_ts/detection/utils/buffer-utils.d.ts +0 -61
- package/dist_ts/detection/utils/buffer-utils.js +0 -127
- package/dist_ts/detection/utils/fragment-manager.d.ts +0 -31
- package/dist_ts/detection/utils/fragment-manager.js +0 -53
- package/dist_ts/detection/utils/parser-utils.d.ts +0 -42
- package/dist_ts/detection/utils/parser-utils.js +0 -63
- package/dist_ts/protocols/common/fragment-handler.d.ts +0 -73
- package/dist_ts/protocols/common/fragment-handler.js +0 -121
- package/dist_ts/protocols/common/index.d.ts +0 -7
- package/dist_ts/protocols/common/index.js +0 -8
- package/dist_ts/protocols/common/types.d.ts +0 -68
- package/dist_ts/protocols/common/types.js +0 -7
- package/dist_ts/protocols/http/parser.d.ts +0 -58
- package/dist_ts/protocols/http/parser.js +0 -184
- package/dist_ts/protocols/proxy/index.d.ts +0 -5
- package/dist_ts/protocols/proxy/index.js +0 -6
- package/dist_ts/protocols/proxy/types.d.ts +0 -47
- package/dist_ts/protocols/proxy/types.js +0 -6
- package/dist_ts/protocols/tls/alerts/index.d.ts +0 -4
- package/dist_ts/protocols/tls/alerts/index.js +0 -5
- package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +0 -150
- package/dist_ts/protocols/tls/alerts/tls-alert.js +0 -226
- package/dist_ts/protocols/tls/index.d.ts +0 -12
- package/dist_ts/protocols/tls/index.js +0 -27
- package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +0 -100
- package/dist_ts/protocols/tls/sni/client-hello-parser.js +0 -463
- package/dist_ts/protocols/tls/sni/index.d.ts +0 -5
- package/dist_ts/protocols/tls/sni/index.js +0 -6
- package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +0 -58
- package/dist_ts/protocols/tls/sni/sni-extraction.js +0 -275
- package/dist_ts/protocols/tls/utils/index.d.ts +0 -4
- package/dist_ts/protocols/tls/utils/index.js +0 -5
- package/dist_ts/protocols/tls/utils/tls-utils.d.ts +0 -158
- package/dist_ts/protocols/tls/utils/tls-utils.js +0 -187
- package/dist_ts/protocols/websocket/constants.d.ts +0 -55
- package/dist_ts/protocols/websocket/constants.js +0 -58
- package/dist_ts/protocols/websocket/index.d.ts +0 -7
- package/dist_ts/protocols/websocket/index.js +0 -8
- package/dist_ts/protocols/websocket/types.d.ts +0 -47
- package/dist_ts/protocols/websocket/types.js +0 -5
- package/dist_ts/protocols/websocket/utils.d.ts +0 -25
- package/dist_ts/protocols/websocket/utils.js +0 -103
- package/dist_ts/routing/router/http-router.d.ts +0 -89
- package/dist_ts/routing/router/http-router.js +0 -205
- package/dist_ts/routing/router/index.d.ts +0 -5
- package/dist_ts/routing/router/index.js +0 -6
- package/dist_ts/tls/index.d.ts +0 -16
- package/dist_ts/tls/index.js +0 -24
- package/dist_ts/tls/sni/index.d.ts +0 -4
- package/dist_ts/tls/sni/index.js +0 -5
- package/dist_ts/tls/sni/sni-handler.d.ts +0 -154
- package/dist_ts/tls/sni/sni-handler.js +0 -191
- package/ts/core/events/index.ts +0 -3
- package/ts/core/models/socket-augmentation.ts +0 -38
- package/ts/core/utils/async-utils.ts +0 -275
- package/ts/core/utils/binary-heap.ts +0 -225
- package/ts/core/utils/enhanced-connection-pool.ts +0 -425
- package/ts/core/utils/fs-utils.ts +0 -270
- package/ts/core/utils/ip-utils.ts +0 -303
- package/ts/core/utils/lifecycle-component.ts +0 -251
- package/ts/core/utils/log-deduplicator.ts +0 -370
- package/ts/core/utils/security-utils.ts +0 -305
- package/ts/core/utils/shared-security-manager.ts +0 -470
- package/ts/core/utils/socket-utils.ts +0 -322
- package/ts/core/utils/template-utils.ts +0 -124
- package/ts/core/utils/validation-utils.ts +0 -177
- package/ts/core/utils/websocket-utils.ts +0 -33
- package/ts/detection/detectors/http-detector.ts +0 -127
- package/ts/detection/detectors/quick-detector.ts +0 -148
- package/ts/detection/detectors/routing-extractor.ts +0 -147
- package/ts/detection/detectors/tls-detector.ts +0 -223
- package/ts/detection/index.ts +0 -25
- package/ts/detection/models/detection-types.ts +0 -102
- package/ts/detection/models/interfaces.ts +0 -115
- package/ts/detection/protocol-detector.ts +0 -319
- package/ts/detection/utils/buffer-utils.ts +0 -141
- package/ts/detection/utils/fragment-manager.ts +0 -64
- package/ts/detection/utils/parser-utils.ts +0 -77
- package/ts/protocols/common/fragment-handler.ts +0 -167
- package/ts/protocols/common/index.ts +0 -8
- package/ts/protocols/common/types.ts +0 -76
- package/ts/protocols/http/parser.ts +0 -219
- package/ts/protocols/proxy/index.ts +0 -6
- package/ts/protocols/proxy/types.ts +0 -53
- package/ts/protocols/tls/alerts/index.ts +0 -3
- package/ts/protocols/tls/alerts/tls-alert.ts +0 -259
- package/ts/protocols/tls/index.ts +0 -37
- package/ts/protocols/tls/sni/client-hello-parser.ts +0 -629
- package/ts/protocols/tls/sni/index.ts +0 -6
- package/ts/protocols/tls/sni/sni-extraction.ts +0 -353
- package/ts/protocols/tls/utils/index.ts +0 -3
- package/ts/protocols/tls/utils/tls-utils.ts +0 -201
- package/ts/protocols/websocket/constants.ts +0 -60
- package/ts/protocols/websocket/index.ts +0 -8
- package/ts/protocols/websocket/types.ts +0 -53
- package/ts/protocols/websocket/utils.ts +0 -98
- package/ts/routing/router/http-router.ts +0 -266
- package/ts/routing/router/index.ts +0 -7
- package/ts/tls/index.ts +0 -29
- package/ts/tls/sni/index.ts +0 -3
- package/ts/tls/sni/sni-handler.ts +0 -264
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
|
|
3
|
-
export interface CleanupOptions {
|
|
4
|
-
immediate?: boolean; // Force immediate destruction
|
|
5
|
-
allowDrain?: boolean; // Allow write buffer to drain
|
|
6
|
-
gracePeriod?: number; // Ms to wait before force close
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface SafeSocketOptions {
|
|
10
|
-
port: number;
|
|
11
|
-
host: string;
|
|
12
|
-
onError?: (error: Error) => void;
|
|
13
|
-
onConnect?: () => void;
|
|
14
|
-
timeout?: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Safely cleanup a socket by removing all listeners and destroying it
|
|
19
|
-
* @param socket The socket to cleanup
|
|
20
|
-
* @param socketName Optional name for logging
|
|
21
|
-
* @param options Cleanup options
|
|
22
|
-
*/
|
|
23
|
-
export function cleanupSocket(
|
|
24
|
-
socket: plugins.net.Socket | plugins.tls.TLSSocket | null,
|
|
25
|
-
socketName?: string,
|
|
26
|
-
options: CleanupOptions = {}
|
|
27
|
-
): Promise<void> {
|
|
28
|
-
if (!socket || socket.destroyed) return Promise.resolve();
|
|
29
|
-
|
|
30
|
-
return new Promise<void>((resolve) => {
|
|
31
|
-
const cleanup = () => {
|
|
32
|
-
try {
|
|
33
|
-
// Remove all event listeners
|
|
34
|
-
socket.removeAllListeners();
|
|
35
|
-
|
|
36
|
-
// Destroy if not already destroyed
|
|
37
|
-
if (!socket.destroyed) {
|
|
38
|
-
socket.destroy();
|
|
39
|
-
}
|
|
40
|
-
} catch (err) {
|
|
41
|
-
console.error(`Error cleaning up socket${socketName ? ` (${socketName})` : ''}: ${err}`);
|
|
42
|
-
}
|
|
43
|
-
resolve();
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
if (options.immediate) {
|
|
47
|
-
// Immediate cleanup (old behavior)
|
|
48
|
-
socket.unpipe();
|
|
49
|
-
cleanup();
|
|
50
|
-
} else if (options.allowDrain && socket.writable) {
|
|
51
|
-
// Allow pending writes to complete
|
|
52
|
-
socket.end(() => cleanup());
|
|
53
|
-
|
|
54
|
-
// Force cleanup after grace period
|
|
55
|
-
if (options.gracePeriod) {
|
|
56
|
-
setTimeout(() => {
|
|
57
|
-
if (!socket.destroyed) {
|
|
58
|
-
cleanup();
|
|
59
|
-
}
|
|
60
|
-
}, options.gracePeriod);
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
// Default: immediate cleanup
|
|
64
|
-
socket.unpipe();
|
|
65
|
-
cleanup();
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Create independent cleanup handlers for paired sockets that support half-open connections
|
|
73
|
-
* @param clientSocket The client socket
|
|
74
|
-
* @param serverSocket The server socket
|
|
75
|
-
* @param onBothClosed Callback when both sockets are closed
|
|
76
|
-
* @returns Independent cleanup functions for each socket
|
|
77
|
-
*/
|
|
78
|
-
export function createIndependentSocketHandlers(
|
|
79
|
-
clientSocket: plugins.net.Socket | plugins.tls.TLSSocket,
|
|
80
|
-
serverSocket: plugins.net.Socket | plugins.tls.TLSSocket,
|
|
81
|
-
onBothClosed: (reason: string) => void,
|
|
82
|
-
options: { enableHalfOpen?: boolean } = {}
|
|
83
|
-
): { cleanupClient: (reason: string) => Promise<void>, cleanupServer: (reason: string) => Promise<void> } {
|
|
84
|
-
let clientClosed = false;
|
|
85
|
-
let serverClosed = false;
|
|
86
|
-
let clientReason = '';
|
|
87
|
-
let serverReason = '';
|
|
88
|
-
|
|
89
|
-
const checkBothClosed = () => {
|
|
90
|
-
if (clientClosed && serverClosed) {
|
|
91
|
-
onBothClosed(`client: ${clientReason}, server: ${serverReason}`);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const cleanupClient = async (reason: string) => {
|
|
96
|
-
if (clientClosed) return;
|
|
97
|
-
clientClosed = true;
|
|
98
|
-
clientReason = reason;
|
|
99
|
-
|
|
100
|
-
// Default behavior: close both sockets when one closes (required for proxy chains)
|
|
101
|
-
if (!serverClosed && !options.enableHalfOpen) {
|
|
102
|
-
serverSocket.destroy();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Half-open support (opt-in only)
|
|
106
|
-
if (!serverClosed && serverSocket.writable && options.enableHalfOpen) {
|
|
107
|
-
// Half-close: stop reading from client, let server finish
|
|
108
|
-
clientSocket.pause();
|
|
109
|
-
clientSocket.unpipe(serverSocket);
|
|
110
|
-
await cleanupSocket(clientSocket, 'client', { allowDrain: true, gracePeriod: 5000 });
|
|
111
|
-
} else {
|
|
112
|
-
await cleanupSocket(clientSocket, 'client', { immediate: true });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
checkBothClosed();
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const cleanupServer = async (reason: string) => {
|
|
119
|
-
if (serverClosed) return;
|
|
120
|
-
serverClosed = true;
|
|
121
|
-
serverReason = reason;
|
|
122
|
-
|
|
123
|
-
// Default behavior: close both sockets when one closes (required for proxy chains)
|
|
124
|
-
if (!clientClosed && !options.enableHalfOpen) {
|
|
125
|
-
clientSocket.destroy();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Half-open support (opt-in only)
|
|
129
|
-
if (!clientClosed && clientSocket.writable && options.enableHalfOpen) {
|
|
130
|
-
// Half-close: stop reading from server, let client finish
|
|
131
|
-
serverSocket.pause();
|
|
132
|
-
serverSocket.unpipe(clientSocket);
|
|
133
|
-
await cleanupSocket(serverSocket, 'server', { allowDrain: true, gracePeriod: 5000 });
|
|
134
|
-
} else {
|
|
135
|
-
await cleanupSocket(serverSocket, 'server', { immediate: true });
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
checkBothClosed();
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
return { cleanupClient, cleanupServer };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Setup socket error and close handlers with proper cleanup
|
|
146
|
-
* @param socket The socket to setup handlers for
|
|
147
|
-
* @param handleClose The cleanup function to call
|
|
148
|
-
* @param handleTimeout Optional custom timeout handler
|
|
149
|
-
* @param errorPrefix Optional prefix for error messages
|
|
150
|
-
*/
|
|
151
|
-
export function setupSocketHandlers(
|
|
152
|
-
socket: plugins.net.Socket | plugins.tls.TLSSocket,
|
|
153
|
-
handleClose: (reason: string) => void,
|
|
154
|
-
handleTimeout?: (socket: plugins.net.Socket | plugins.tls.TLSSocket) => void,
|
|
155
|
-
errorPrefix?: string
|
|
156
|
-
): void {
|
|
157
|
-
socket.on('error', (error) => {
|
|
158
|
-
const prefix = errorPrefix || 'Socket';
|
|
159
|
-
handleClose(`${prefix}_error: ${error.message}`);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
socket.on('close', () => {
|
|
163
|
-
const prefix = errorPrefix || 'socket';
|
|
164
|
-
handleClose(`${prefix}_closed`);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
socket.on('timeout', () => {
|
|
168
|
-
if (handleTimeout) {
|
|
169
|
-
handleTimeout(socket); // Custom timeout handling
|
|
170
|
-
} else {
|
|
171
|
-
// Default: just log, don't close
|
|
172
|
-
console.warn(`Socket timeout: ${errorPrefix || 'socket'}`);
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Setup bidirectional data forwarding between two sockets with proper cleanup
|
|
179
|
-
* @param clientSocket The client/incoming socket
|
|
180
|
-
* @param serverSocket The server/outgoing socket
|
|
181
|
-
* @param handlers Object containing optional handlers for data and cleanup
|
|
182
|
-
* @returns Cleanup functions for both sockets
|
|
183
|
-
*/
|
|
184
|
-
export function setupBidirectionalForwarding(
|
|
185
|
-
clientSocket: plugins.net.Socket | plugins.tls.TLSSocket,
|
|
186
|
-
serverSocket: plugins.net.Socket | plugins.tls.TLSSocket,
|
|
187
|
-
handlers: {
|
|
188
|
-
onClientData?: (chunk: Buffer) => void;
|
|
189
|
-
onServerData?: (chunk: Buffer) => void;
|
|
190
|
-
onCleanup: (reason: string) => void;
|
|
191
|
-
enableHalfOpen?: boolean;
|
|
192
|
-
}
|
|
193
|
-
): { cleanupClient: (reason: string) => Promise<void>, cleanupServer: (reason: string) => Promise<void> } {
|
|
194
|
-
// Set up cleanup handlers
|
|
195
|
-
const { cleanupClient, cleanupServer } = createIndependentSocketHandlers(
|
|
196
|
-
clientSocket,
|
|
197
|
-
serverSocket,
|
|
198
|
-
handlers.onCleanup,
|
|
199
|
-
{ enableHalfOpen: handlers.enableHalfOpen }
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
// Set up error and close handlers
|
|
203
|
-
setupSocketHandlers(clientSocket, cleanupClient, undefined, 'client');
|
|
204
|
-
setupSocketHandlers(serverSocket, cleanupServer, undefined, 'server');
|
|
205
|
-
|
|
206
|
-
// Set up data forwarding with backpressure handling
|
|
207
|
-
clientSocket.on('data', (chunk: Buffer) => {
|
|
208
|
-
if (handlers.onClientData) {
|
|
209
|
-
handlers.onClientData(chunk);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (serverSocket.writable) {
|
|
213
|
-
const flushed = serverSocket.write(chunk);
|
|
214
|
-
|
|
215
|
-
// Handle backpressure
|
|
216
|
-
if (!flushed) {
|
|
217
|
-
clientSocket.pause();
|
|
218
|
-
serverSocket.once('drain', () => {
|
|
219
|
-
if (!clientSocket.destroyed) {
|
|
220
|
-
clientSocket.resume();
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
serverSocket.on('data', (chunk: Buffer) => {
|
|
228
|
-
if (handlers.onServerData) {
|
|
229
|
-
handlers.onServerData(chunk);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (clientSocket.writable) {
|
|
233
|
-
const flushed = clientSocket.write(chunk);
|
|
234
|
-
|
|
235
|
-
// Handle backpressure
|
|
236
|
-
if (!flushed) {
|
|
237
|
-
serverSocket.pause();
|
|
238
|
-
clientSocket.once('drain', () => {
|
|
239
|
-
if (!serverSocket.destroyed) {
|
|
240
|
-
serverSocket.resume();
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
return { cleanupClient, cleanupServer };
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Create a socket with immediate error handling to prevent crashes
|
|
252
|
-
* @param options Socket creation options
|
|
253
|
-
* @returns The created socket
|
|
254
|
-
*/
|
|
255
|
-
export function createSocketWithErrorHandler(options: SafeSocketOptions): plugins.net.Socket {
|
|
256
|
-
const { port, host, onError, onConnect, timeout } = options;
|
|
257
|
-
|
|
258
|
-
// Create socket with immediate error handler attachment
|
|
259
|
-
const socket = new plugins.net.Socket();
|
|
260
|
-
|
|
261
|
-
// Track if connected
|
|
262
|
-
let connected = false;
|
|
263
|
-
let connectionTimeout: NodeJS.Timeout | null = null;
|
|
264
|
-
|
|
265
|
-
// Attach error handler BEFORE connecting to catch immediate errors
|
|
266
|
-
socket.on('error', (error) => {
|
|
267
|
-
console.error(`Socket connection error to ${host}:${port}: ${error.message}`);
|
|
268
|
-
// Clear the connection timeout if it exists
|
|
269
|
-
if (connectionTimeout) {
|
|
270
|
-
clearTimeout(connectionTimeout);
|
|
271
|
-
connectionTimeout = null;
|
|
272
|
-
}
|
|
273
|
-
if (onError) {
|
|
274
|
-
onError(error);
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// Attach connect handler
|
|
279
|
-
const handleConnect = () => {
|
|
280
|
-
connected = true;
|
|
281
|
-
// Clear the connection timeout
|
|
282
|
-
if (connectionTimeout) {
|
|
283
|
-
clearTimeout(connectionTimeout);
|
|
284
|
-
connectionTimeout = null;
|
|
285
|
-
}
|
|
286
|
-
// Set inactivity timeout if provided (after connection is established)
|
|
287
|
-
if (timeout) {
|
|
288
|
-
socket.setTimeout(timeout);
|
|
289
|
-
}
|
|
290
|
-
if (onConnect) {
|
|
291
|
-
onConnect();
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
socket.on('connect', handleConnect);
|
|
296
|
-
|
|
297
|
-
// Implement connection establishment timeout
|
|
298
|
-
if (timeout) {
|
|
299
|
-
connectionTimeout = setTimeout(() => {
|
|
300
|
-
if (!connected && !socket.destroyed) {
|
|
301
|
-
// Connection timed out - destroy the socket
|
|
302
|
-
const error = new Error(`Connection timeout after ${timeout}ms to ${host}:${port}`);
|
|
303
|
-
(error as any).code = 'ETIMEDOUT';
|
|
304
|
-
|
|
305
|
-
console.error(`Socket connection timeout to ${host}:${port} after ${timeout}ms`);
|
|
306
|
-
|
|
307
|
-
// Destroy the socket
|
|
308
|
-
socket.destroy();
|
|
309
|
-
|
|
310
|
-
// Call error handler
|
|
311
|
-
if (onError) {
|
|
312
|
-
onError(error);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}, timeout);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Now attempt to connect - any immediate errors will be caught
|
|
319
|
-
socket.connect(port, host);
|
|
320
|
-
|
|
321
|
-
return socket;
|
|
322
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import type { IRouteContext } from '../models/route-context.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Utility class for resolving template variables in strings
|
|
5
|
-
*/
|
|
6
|
-
export class TemplateUtils {
|
|
7
|
-
/**
|
|
8
|
-
* Resolve template variables in a string using the route context
|
|
9
|
-
* Supports variables like {domain}, {path}, {clientIp}, etc.
|
|
10
|
-
*
|
|
11
|
-
* @param template The template string with {variables}
|
|
12
|
-
* @param context The route context with values
|
|
13
|
-
* @returns The resolved string
|
|
14
|
-
*/
|
|
15
|
-
public static resolveTemplateVariables(template: string, context: IRouteContext): string {
|
|
16
|
-
if (!template) {
|
|
17
|
-
return template;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Replace variables with values from context
|
|
21
|
-
return template.replace(/\{([a-zA-Z0-9_\.]+)\}/g, (match, varName) => {
|
|
22
|
-
// Handle nested properties with dot notation (e.g., {headers.host})
|
|
23
|
-
if (varName.includes('.')) {
|
|
24
|
-
const parts = varName.split('.');
|
|
25
|
-
let current: any = context;
|
|
26
|
-
|
|
27
|
-
// Traverse nested object structure
|
|
28
|
-
for (const part of parts) {
|
|
29
|
-
if (current === undefined || current === null) {
|
|
30
|
-
return match; // Return original if path doesn't exist
|
|
31
|
-
}
|
|
32
|
-
current = current[part];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Return the resolved value if it exists
|
|
36
|
-
if (current !== undefined && current !== null) {
|
|
37
|
-
return TemplateUtils.convertToString(current);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return match;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Direct property access
|
|
44
|
-
const value = context[varName as keyof IRouteContext];
|
|
45
|
-
if (value === undefined) {
|
|
46
|
-
return match; // Keep the original {variable} if not found
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Convert value to string
|
|
50
|
-
return TemplateUtils.convertToString(value);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Safely convert a value to a string
|
|
56
|
-
*
|
|
57
|
-
* @param value Any value to convert to string
|
|
58
|
-
* @returns String representation or original match for complex objects
|
|
59
|
-
*/
|
|
60
|
-
private static convertToString(value: any): string {
|
|
61
|
-
if (value === null || value === undefined) {
|
|
62
|
-
return '';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (typeof value === 'string') {
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
70
|
-
return value.toString();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (Array.isArray(value)) {
|
|
74
|
-
return value.join(',');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (typeof value === 'object') {
|
|
78
|
-
try {
|
|
79
|
-
return JSON.stringify(value);
|
|
80
|
-
} catch (e) {
|
|
81
|
-
return '[Object]';
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return String(value);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Resolve template variables in header values
|
|
90
|
-
*
|
|
91
|
-
* @param headers Header object with potential template variables
|
|
92
|
-
* @param context Route context for variable resolution
|
|
93
|
-
* @returns New header object with resolved values
|
|
94
|
-
*/
|
|
95
|
-
public static resolveHeaderTemplates(
|
|
96
|
-
headers: Record<string, string>,
|
|
97
|
-
context: IRouteContext
|
|
98
|
-
): Record<string, string> {
|
|
99
|
-
const result: Record<string, string> = {};
|
|
100
|
-
|
|
101
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
102
|
-
// Skip special directive headers (starting with !)
|
|
103
|
-
if (value.startsWith('!')) {
|
|
104
|
-
result[key] = value;
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Resolve template variables in the header value
|
|
109
|
-
result[key] = TemplateUtils.resolveTemplateVariables(value, context);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Check if a string contains template variables
|
|
117
|
-
*
|
|
118
|
-
* @param str String to check for template variables
|
|
119
|
-
* @returns True if string contains template variables
|
|
120
|
-
*/
|
|
121
|
-
public static containsTemplateVariables(str: string): boolean {
|
|
122
|
-
return !!str && /\{([a-zA-Z0-9_\.]+)\}/g.test(str);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import type { IDomainOptions, IAcmeOptions } from '../models/common-types.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Collection of validation utilities for configuration and domain options
|
|
6
|
-
*/
|
|
7
|
-
export class ValidationUtils {
|
|
8
|
-
/**
|
|
9
|
-
* Validates domain configuration options
|
|
10
|
-
*
|
|
11
|
-
* @param domainOptions The domain options to validate
|
|
12
|
-
* @returns An object with validation result and error message if invalid
|
|
13
|
-
*/
|
|
14
|
-
public static validateDomainOptions(domainOptions: IDomainOptions): { isValid: boolean; error?: string } {
|
|
15
|
-
if (!domainOptions) {
|
|
16
|
-
return { isValid: false, error: 'Domain options cannot be null or undefined' };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (!domainOptions.domainName) {
|
|
20
|
-
return { isValid: false, error: 'Domain name is required' };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Check domain pattern
|
|
24
|
-
if (!this.isValidDomainName(domainOptions.domainName)) {
|
|
25
|
-
return { isValid: false, error: `Invalid domain name: ${domainOptions.domainName}` };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Validate forward config if provided
|
|
29
|
-
if (domainOptions.forward) {
|
|
30
|
-
if (!domainOptions.forward.ip) {
|
|
31
|
-
return { isValid: false, error: 'Forward IP is required when forward is specified' };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!domainOptions.forward.port) {
|
|
35
|
-
return { isValid: false, error: 'Forward port is required when forward is specified' };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!this.isValidPort(domainOptions.forward.port)) {
|
|
39
|
-
return { isValid: false, error: `Invalid forward port: ${domainOptions.forward.port}` };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Validate ACME forward config if provided
|
|
44
|
-
if (domainOptions.acmeForward) {
|
|
45
|
-
if (!domainOptions.acmeForward.ip) {
|
|
46
|
-
return { isValid: false, error: 'ACME forward IP is required when acmeForward is specified' };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!domainOptions.acmeForward.port) {
|
|
50
|
-
return { isValid: false, error: 'ACME forward port is required when acmeForward is specified' };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!this.isValidPort(domainOptions.acmeForward.port)) {
|
|
54
|
-
return { isValid: false, error: `Invalid ACME forward port: ${domainOptions.acmeForward.port}` };
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return { isValid: true };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Validates ACME configuration options
|
|
63
|
-
*
|
|
64
|
-
* @param acmeOptions The ACME options to validate
|
|
65
|
-
* @returns An object with validation result and error message if invalid
|
|
66
|
-
*/
|
|
67
|
-
public static validateAcmeOptions(acmeOptions: IAcmeOptions): { isValid: boolean; error?: string } {
|
|
68
|
-
if (!acmeOptions) {
|
|
69
|
-
return { isValid: false, error: 'ACME options cannot be null or undefined' };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (acmeOptions.enabled) {
|
|
73
|
-
if (!acmeOptions.accountEmail) {
|
|
74
|
-
return { isValid: false, error: 'Account email is required when ACME is enabled' };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!this.isValidEmail(acmeOptions.accountEmail)) {
|
|
78
|
-
return { isValid: false, error: `Invalid email: ${acmeOptions.accountEmail}` };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (acmeOptions.port && !this.isValidPort(acmeOptions.port)) {
|
|
82
|
-
return { isValid: false, error: `Invalid ACME port: ${acmeOptions.port}` };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (acmeOptions.httpsRedirectPort && !this.isValidPort(acmeOptions.httpsRedirectPort)) {
|
|
86
|
-
return { isValid: false, error: `Invalid HTTPS redirect port: ${acmeOptions.httpsRedirectPort}` };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (acmeOptions.renewThresholdDays && acmeOptions.renewThresholdDays < 1) {
|
|
90
|
-
return { isValid: false, error: 'Renew threshold days must be greater than 0' };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (acmeOptions.renewCheckIntervalHours && acmeOptions.renewCheckIntervalHours < 1) {
|
|
94
|
-
return { isValid: false, error: 'Renew check interval hours must be greater than 0' };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return { isValid: true };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Validates a port number
|
|
103
|
-
*
|
|
104
|
-
* @param port The port to validate
|
|
105
|
-
* @returns true if the port is valid, false otherwise
|
|
106
|
-
*/
|
|
107
|
-
public static isValidPort(port: number): boolean {
|
|
108
|
-
return typeof port === 'number' && port > 0 && port <= 65535 && Number.isInteger(port);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Validates a domain name
|
|
113
|
-
*
|
|
114
|
-
* @param domain The domain name to validate
|
|
115
|
-
* @returns true if the domain name is valid, false otherwise
|
|
116
|
-
*/
|
|
117
|
-
public static isValidDomainName(domain: string): boolean {
|
|
118
|
-
if (!domain || typeof domain !== 'string') {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Wildcard domain check (*.example.com)
|
|
123
|
-
if (domain.startsWith('*.')) {
|
|
124
|
-
domain = domain.substring(2);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Simple domain validation pattern
|
|
128
|
-
const domainPattern = /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
129
|
-
return domainPattern.test(domain);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Validates an email address
|
|
134
|
-
*
|
|
135
|
-
* @param email The email to validate
|
|
136
|
-
* @returns true if the email is valid, false otherwise
|
|
137
|
-
*/
|
|
138
|
-
public static isValidEmail(email: string): boolean {
|
|
139
|
-
if (!email || typeof email !== 'string') {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Basic email validation pattern
|
|
144
|
-
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
145
|
-
return emailPattern.test(email);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Validates a certificate format (PEM)
|
|
150
|
-
*
|
|
151
|
-
* @param cert The certificate content to validate
|
|
152
|
-
* @returns true if the certificate appears to be in PEM format, false otherwise
|
|
153
|
-
*/
|
|
154
|
-
public static isValidCertificate(cert: string): boolean {
|
|
155
|
-
if (!cert || typeof cert !== 'string') {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return cert.includes('-----BEGIN CERTIFICATE-----') &&
|
|
160
|
-
cert.includes('-----END CERTIFICATE-----');
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Validates a private key format (PEM)
|
|
165
|
-
*
|
|
166
|
-
* @param key The private key content to validate
|
|
167
|
-
* @returns true if the key appears to be in PEM format, false otherwise
|
|
168
|
-
*/
|
|
169
|
-
public static isValidPrivateKey(key: string): boolean {
|
|
170
|
-
if (!key || typeof key !== 'string') {
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return key.includes('-----BEGIN PRIVATE KEY-----') &&
|
|
175
|
-
key.includes('-----END PRIVATE KEY-----');
|
|
176
|
-
}
|
|
177
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebSocket utility functions
|
|
3
|
-
*
|
|
4
|
-
* This module provides smartproxy-specific WebSocket utilities
|
|
5
|
-
* and re-exports protocol utilities from the protocols module
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Import and re-export from protocols
|
|
9
|
-
import { getMessageSize as protocolGetMessageSize, toBuffer as protocolToBuffer } from '../../protocols/websocket/index.js';
|
|
10
|
-
export type { RawData } from '../../protocols/websocket/index.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Get the length of a WebSocket message regardless of its type
|
|
14
|
-
* (handles all possible WebSocket message data types)
|
|
15
|
-
*
|
|
16
|
-
* @param data - The data message from WebSocket (could be any RawData type)
|
|
17
|
-
* @returns The length of the data in bytes
|
|
18
|
-
*/
|
|
19
|
-
export function getMessageSize(data: import('../../protocols/websocket/index.js').RawData): number {
|
|
20
|
-
// Delegate to protocol implementation
|
|
21
|
-
return protocolGetMessageSize(data);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Convert any raw WebSocket data to Buffer for consistent handling
|
|
26
|
-
*
|
|
27
|
-
* @param data - The data message from WebSocket (could be any RawData type)
|
|
28
|
-
* @returns A Buffer containing the data
|
|
29
|
-
*/
|
|
30
|
-
export function toBuffer(data: import('../../protocols/websocket/index.js').RawData): Buffer {
|
|
31
|
-
// Delegate to protocol implementation
|
|
32
|
-
return protocolToBuffer(data);
|
|
33
|
-
}
|