@push.rocks/smartproxy 3.23.0 → 3.24.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/classes.networkproxy.d.ts +90 -8
- package/dist_ts/classes.networkproxy.js +605 -221
- package/dist_ts/classes.portproxy.d.ts +5 -0
- package/dist_ts/classes.portproxy.js +251 -80
- package/package.json +8 -8
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.networkproxy.ts +743 -268
- package/ts/classes.portproxy.ts +285 -84
|
@@ -4,13 +4,41 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
export class NetworkProxy {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new NetworkProxy instance
|
|
9
|
+
*/
|
|
7
10
|
constructor(optionsArg) {
|
|
8
11
|
this.proxyConfigs = [];
|
|
12
|
+
this.defaultHeaders = {};
|
|
13
|
+
// State tracking
|
|
9
14
|
this.router = new ProxyRouter();
|
|
10
15
|
this.socketMap = new plugins.lik.ObjectMap();
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
16
|
+
this.activeContexts = new Set();
|
|
17
|
+
this.connectedClients = 0;
|
|
18
|
+
this.startTime = 0;
|
|
19
|
+
this.requestsServed = 0;
|
|
20
|
+
this.failedRequests = 0;
|
|
21
|
+
this.certificateCache = new Map();
|
|
22
|
+
// Set default options
|
|
23
|
+
this.options = {
|
|
24
|
+
port: optionsArg.port,
|
|
25
|
+
maxConnections: optionsArg.maxConnections || 10000,
|
|
26
|
+
keepAliveTimeout: optionsArg.keepAliveTimeout || 120000, // 2 minutes
|
|
27
|
+
headersTimeout: optionsArg.headersTimeout || 60000, // 1 minute
|
|
28
|
+
logLevel: optionsArg.logLevel || 'info',
|
|
29
|
+
cors: optionsArg.cors || {
|
|
30
|
+
allowOrigin: '*',
|
|
31
|
+
allowMethods: 'GET, POST, PUT, DELETE, OPTIONS',
|
|
32
|
+
allowHeaders: 'Content-Type, Authorization',
|
|
33
|
+
maxAge: 86400
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
this.loadDefaultCertificates();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Loads default certificates from the filesystem
|
|
40
|
+
*/
|
|
41
|
+
loadDefaultCertificates() {
|
|
14
42
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
43
|
const certPath = path.join(__dirname, '..', 'assets', 'certs');
|
|
16
44
|
try {
|
|
@@ -18,288 +46,644 @@ export class NetworkProxy {
|
|
|
18
46
|
key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
|
|
19
47
|
cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
|
|
20
48
|
};
|
|
49
|
+
this.log('info', 'Default certificates loaded successfully');
|
|
21
50
|
}
|
|
22
51
|
catch (error) {
|
|
23
|
-
|
|
24
|
-
|
|
52
|
+
this.log('error', 'Error loading default certificates', error);
|
|
53
|
+
// Generate self-signed fallback certificates
|
|
54
|
+
try {
|
|
55
|
+
// This is a placeholder for actual certificate generation code
|
|
56
|
+
// In a real implementation, you would use a library like selfsigned to generate certs
|
|
57
|
+
this.defaultCertificates = {
|
|
58
|
+
key: "FALLBACK_KEY_CONTENT",
|
|
59
|
+
cert: "FALLBACK_CERT_CONTENT"
|
|
60
|
+
};
|
|
61
|
+
this.log('warn', 'Using fallback self-signed certificates');
|
|
62
|
+
}
|
|
63
|
+
catch (fallbackError) {
|
|
64
|
+
this.log('error', 'Failed to generate fallback certificates', fallbackError);
|
|
65
|
+
throw new Error('Could not load or generate SSL certificates');
|
|
66
|
+
}
|
|
25
67
|
}
|
|
26
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Starts the proxy server
|
|
71
|
+
*/
|
|
27
72
|
async start() {
|
|
28
|
-
|
|
29
|
-
//
|
|
73
|
+
this.startTime = Date.now();
|
|
74
|
+
// Create the HTTPS server
|
|
30
75
|
this.httpsServer = plugins.https.createServer({
|
|
31
76
|
key: this.defaultCertificates.key,
|
|
32
77
|
cert: this.defaultCertificates.cert
|
|
33
|
-
}, (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
78
|
+
}, (req, res) => this.handleRequest(req, res));
|
|
79
|
+
// Configure server timeouts
|
|
80
|
+
this.httpsServer.keepAliveTimeout = this.options.keepAliveTimeout;
|
|
81
|
+
this.httpsServer.headersTimeout = this.options.headersTimeout;
|
|
82
|
+
// Setup connection tracking
|
|
83
|
+
this.setupConnectionTracking();
|
|
84
|
+
// Setup WebSocket support
|
|
85
|
+
this.setupWebsocketSupport();
|
|
86
|
+
// Start metrics collection
|
|
87
|
+
this.setupMetricsCollection();
|
|
88
|
+
// Start the server
|
|
89
|
+
return new Promise((resolve) => {
|
|
90
|
+
this.httpsServer.listen(this.options.port, () => {
|
|
91
|
+
this.log('info', `NetworkProxy started on port ${this.options.port}`);
|
|
92
|
+
resolve();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Sets up tracking of TCP connections
|
|
98
|
+
*/
|
|
99
|
+
setupConnectionTracking() {
|
|
100
|
+
this.httpsServer.on('connection', (connection) => {
|
|
101
|
+
// Check if max connections reached
|
|
102
|
+
if (this.socketMap.getArray().length >= this.options.maxConnections) {
|
|
103
|
+
this.log('warn', `Max connections (${this.options.maxConnections}) reached, rejecting new connection`);
|
|
104
|
+
connection.destroy();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Add connection to tracking
|
|
108
|
+
this.socketMap.add(connection);
|
|
109
|
+
this.connectedClients = this.socketMap.getArray().length;
|
|
110
|
+
this.log('debug', `New connection. Currently ${this.connectedClients} active connections`);
|
|
111
|
+
// Setup connection cleanup handlers
|
|
112
|
+
const cleanupConnection = () => {
|
|
113
|
+
if (this.socketMap.checkForObject(connection)) {
|
|
114
|
+
this.socketMap.remove(connection);
|
|
115
|
+
this.connectedClients = this.socketMap.getArray().length;
|
|
116
|
+
this.log('debug', `Connection closed. ${this.connectedClients} connections remaining`);
|
|
41
117
|
}
|
|
118
|
+
};
|
|
119
|
+
connection.on('close', cleanupConnection);
|
|
120
|
+
connection.on('error', (err) => {
|
|
121
|
+
this.log('debug', 'Connection error', err);
|
|
122
|
+
cleanupConnection();
|
|
123
|
+
});
|
|
124
|
+
connection.on('end', cleanupConnection);
|
|
125
|
+
connection.on('timeout', () => {
|
|
126
|
+
this.log('debug', 'Connection timeout');
|
|
127
|
+
cleanupConnection();
|
|
42
128
|
});
|
|
43
129
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Sets up WebSocket support
|
|
133
|
+
*/
|
|
134
|
+
setupWebsocketSupport() {
|
|
135
|
+
// Create WebSocket server
|
|
136
|
+
this.wsServer = new plugins.ws.WebSocketServer({
|
|
137
|
+
server: this.httpsServer,
|
|
138
|
+
// Add WebSocket specific timeout
|
|
139
|
+
clientTracking: true
|
|
140
|
+
});
|
|
141
|
+
// Handle WebSocket connections
|
|
142
|
+
this.wsServer.on('connection', (wsIncoming, reqArg) => {
|
|
143
|
+
this.handleWebSocketConnection(wsIncoming, reqArg);
|
|
144
|
+
});
|
|
145
|
+
// Set up the heartbeat interval (check every 30 seconds, terminate after 2 minutes of inactivity)
|
|
47
146
|
this.heartbeatInterval = setInterval(() => {
|
|
48
|
-
wsServer.clients.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
else {
|
|
58
|
-
wsIncoming.ping();
|
|
147
|
+
if (this.wsServer.clients.size === 0) {
|
|
148
|
+
return; // Skip if no active connections
|
|
149
|
+
}
|
|
150
|
+
this.log('debug', `WebSocket heartbeat check for ${this.wsServer.clients.size} clients`);
|
|
151
|
+
this.wsServer.clients.forEach((ws) => {
|
|
152
|
+
const wsWithHeartbeat = ws;
|
|
153
|
+
if (wsWithHeartbeat.isAlive === false) {
|
|
154
|
+
this.log('debug', 'Terminating inactive WebSocket connection');
|
|
155
|
+
return wsWithHeartbeat.terminate();
|
|
59
156
|
}
|
|
157
|
+
wsWithHeartbeat.isAlive = false;
|
|
158
|
+
wsWithHeartbeat.ping();
|
|
60
159
|
});
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
|
|
160
|
+
}, 30000);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Sets up metrics collection
|
|
164
|
+
*/
|
|
165
|
+
setupMetricsCollection() {
|
|
166
|
+
this.metricsInterval = setInterval(() => {
|
|
167
|
+
const uptime = Math.floor((Date.now() - this.startTime) / 1000);
|
|
168
|
+
const metrics = {
|
|
169
|
+
uptime,
|
|
170
|
+
activeConnections: this.connectedClients,
|
|
171
|
+
totalRequests: this.requestsServed,
|
|
172
|
+
failedRequests: this.failedRequests,
|
|
173
|
+
activeWebSockets: this.wsServer?.clients.size || 0,
|
|
174
|
+
memoryUsage: process.memoryUsage(),
|
|
175
|
+
activeContexts: Array.from(this.activeContexts)
|
|
176
|
+
};
|
|
177
|
+
this.log('debug', 'Proxy metrics', metrics);
|
|
178
|
+
}, 60000); // Log metrics every minute
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Handles an incoming WebSocket connection
|
|
182
|
+
*/
|
|
183
|
+
handleWebSocketConnection(wsIncoming, reqArg) {
|
|
184
|
+
const wsPath = reqArg.url;
|
|
185
|
+
const wsHost = reqArg.headers.host;
|
|
186
|
+
this.log('info', `WebSocket connection for ${wsHost}${wsPath}`);
|
|
187
|
+
// Setup heartbeat tracking
|
|
188
|
+
wsIncoming.isAlive = true;
|
|
189
|
+
wsIncoming.lastPong = Date.now();
|
|
190
|
+
wsIncoming.on('pong', () => {
|
|
191
|
+
wsIncoming.isAlive = true;
|
|
64
192
|
wsIncoming.lastPong = Date.now();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
193
|
+
});
|
|
194
|
+
// Get the destination configuration
|
|
195
|
+
const wsDestinationConfig = this.router.routeReq(reqArg);
|
|
196
|
+
if (!wsDestinationConfig) {
|
|
197
|
+
this.log('warn', `No route found for WebSocket ${wsHost}${wsPath}`);
|
|
198
|
+
wsIncoming.terminate();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Check authentication if required
|
|
202
|
+
if (wsDestinationConfig.authentication) {
|
|
76
203
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
204
|
+
if (!this.authenticateRequest(reqArg, wsDestinationConfig)) {
|
|
205
|
+
this.log('warn', `WebSocket authentication failed for ${wsHost}${wsPath}`);
|
|
206
|
+
wsIncoming.terminate();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
82
209
|
}
|
|
83
|
-
catch (
|
|
84
|
-
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.log('error', 'WebSocket authentication error', error);
|
|
85
212
|
wsIncoming.terminate();
|
|
86
213
|
return;
|
|
87
214
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
215
|
+
}
|
|
216
|
+
// Setup outgoing WebSocket connection
|
|
217
|
+
let wsOutgoing;
|
|
218
|
+
const outGoingDeferred = plugins.smartpromise.defer();
|
|
219
|
+
try {
|
|
220
|
+
const wsTarget = `ws://${wsDestinationConfig.destinationIp}:${wsDestinationConfig.destinationPort}${reqArg.url}`;
|
|
221
|
+
this.log('debug', `Proxying WebSocket to ${wsTarget}`);
|
|
222
|
+
wsOutgoing = new plugins.wsDefault(wsTarget);
|
|
223
|
+
wsOutgoing.on('open', () => {
|
|
224
|
+
this.log('debug', 'Outgoing WebSocket connection established');
|
|
225
|
+
outGoingDeferred.resolve();
|
|
226
|
+
});
|
|
227
|
+
wsOutgoing.on('error', (error) => {
|
|
228
|
+
this.log('error', 'Outgoing WebSocket error', error);
|
|
229
|
+
outGoingDeferred.reject(error);
|
|
230
|
+
if (wsIncoming.readyState === wsIncoming.OPEN) {
|
|
231
|
+
wsIncoming.terminate();
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
this.log('error', 'Failed to create outgoing WebSocket connection', err);
|
|
237
|
+
wsIncoming.terminate();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
// Handle message forwarding from client to backend
|
|
241
|
+
wsIncoming.on('message', async (message, isBinary) => {
|
|
242
|
+
try {
|
|
243
|
+
// Wait for outgoing connection to be ready
|
|
244
|
+
await outGoingDeferred.promise;
|
|
245
|
+
// Only forward if both connections are still open
|
|
246
|
+
if (wsOutgoing.readyState === wsOutgoing.OPEN) {
|
|
91
247
|
wsOutgoing.send(message, { binary: isBinary });
|
|
92
248
|
}
|
|
93
|
-
|
|
94
|
-
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
this.log('error', 'Error forwarding WebSocket message to backend', error);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
// Handle message forwarding from backend to client
|
|
255
|
+
wsOutgoing.on('message', (message, isBinary) => {
|
|
256
|
+
try {
|
|
257
|
+
// Only forward if the incoming connection is still open
|
|
258
|
+
if (wsIncoming.readyState === wsIncoming.OPEN) {
|
|
259
|
+
wsIncoming.send(message, { binary: isBinary });
|
|
95
260
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
this.log('error', 'Error forwarding WebSocket message to client', error);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
// Clean up connections when either side closes
|
|
267
|
+
wsIncoming.on('close', (code, reason) => {
|
|
268
|
+
this.log('debug', `Incoming WebSocket closed: ${code} - ${reason}`);
|
|
269
|
+
if (wsOutgoing && wsOutgoing.readyState !== wsOutgoing.CLOSED) {
|
|
98
270
|
try {
|
|
99
|
-
|
|
271
|
+
// Validate close code (must be 1000-4999) or use 1000 as default
|
|
272
|
+
const validCode = (code >= 1000 && code <= 4999) ? code : 1000;
|
|
273
|
+
wsOutgoing.close(validCode, reason.toString() || '');
|
|
100
274
|
}
|
|
101
275
|
catch (error) {
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
const terminateWsOutgoing = () => {
|
|
106
|
-
if (wsOutgoing) {
|
|
276
|
+
this.log('error', 'Error closing outgoing WebSocket', error);
|
|
107
277
|
wsOutgoing.terminate();
|
|
108
|
-
console.log('Terminated outgoing ws.');
|
|
109
278
|
}
|
|
110
|
-
}
|
|
111
|
-
wsIncoming.on('error', terminateWsOutgoing);
|
|
112
|
-
wsIncoming.on('close', terminateWsOutgoing);
|
|
113
|
-
const terminateWsIncoming = () => {
|
|
114
|
-
if (wsIncoming) {
|
|
115
|
-
wsIncoming.terminate();
|
|
116
|
-
console.log('Terminated incoming ws.');
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
wsOutgoing.on('error', terminateWsIncoming);
|
|
120
|
-
wsOutgoing.on('close', terminateWsIncoming);
|
|
279
|
+
}
|
|
121
280
|
});
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
this.socketMap.remove(connection);
|
|
130
|
-
console.log(`Removed connection. ${this.socketMap.getArray().length} sockets remaining.`);
|
|
131
|
-
connection.destroy();
|
|
281
|
+
wsOutgoing.on('close', (code, reason) => {
|
|
282
|
+
this.log('debug', `Outgoing WebSocket closed: ${code} - ${reason}`);
|
|
283
|
+
if (wsIncoming && wsIncoming.readyState !== wsIncoming.CLOSED) {
|
|
284
|
+
try {
|
|
285
|
+
// Validate close code (must be 1000-4999) or use 1000 as default
|
|
286
|
+
const validCode = (code >= 1000 && code <= 4999) ? code : 1000;
|
|
287
|
+
wsIncoming.close(validCode, reason.toString() || '');
|
|
132
288
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
289
|
+
catch (error) {
|
|
290
|
+
this.log('error', 'Error closing incoming WebSocket', error);
|
|
291
|
+
wsIncoming.terminate();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
138
294
|
});
|
|
139
|
-
this.httpsServer.listen(this.options.port);
|
|
140
|
-
console.log(`NetworkProxy -> OK: now listening for new connections on port ${this.options.port}`);
|
|
141
295
|
}
|
|
142
296
|
/**
|
|
143
|
-
*
|
|
297
|
+
* Handles an HTTP/HTTPS request
|
|
144
298
|
*/
|
|
145
299
|
async handleRequest(originRequest, originResponse) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
300
|
+
this.requestsServed++;
|
|
301
|
+
const startTime = Date.now();
|
|
302
|
+
const reqId = `req_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
303
|
+
try {
|
|
304
|
+
const reqPath = plugins.url.parse(originRequest.url).path;
|
|
305
|
+
this.log('info', `[${reqId}] ${originRequest.method} ${originRequest.headers.host}${reqPath}`);
|
|
306
|
+
// Handle preflight OPTIONS requests for CORS
|
|
307
|
+
if (originRequest.method === 'OPTIONS' && this.options.cors) {
|
|
308
|
+
this.handleCorsRequest(originRequest, originResponse);
|
|
309
|
+
return;
|
|
151
310
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const authHeader = originRequest.headers.authorization;
|
|
167
|
-
if (!authHeader) {
|
|
168
|
-
return endOriginReqRes(401, 'Authentication required', {
|
|
169
|
-
'WWW-Authenticate': 'Basic realm="Access to the staging site", charset="UTF-8"',
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
if (!authHeader.includes('Basic ')) {
|
|
173
|
-
return endOriginReqRes(401, 'Authentication required', {
|
|
174
|
-
'WWW-Authenticate': 'Basic realm="Access to the staging site", charset="UTF-8"',
|
|
311
|
+
// Get destination configuration
|
|
312
|
+
const destinationConfig = this.router.routeReq(originRequest);
|
|
313
|
+
if (!destinationConfig) {
|
|
314
|
+
this.log('warn', `[${reqId}] No route found for ${originRequest.headers.host}`);
|
|
315
|
+
this.sendErrorResponse(originResponse, 404, 'Not Found: No matching route');
|
|
316
|
+
this.failedRequests++;
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
// Handle authentication if configured
|
|
320
|
+
if (destinationConfig.authentication) {
|
|
321
|
+
try {
|
|
322
|
+
if (!this.authenticateRequest(originRequest, destinationConfig)) {
|
|
323
|
+
this.sendErrorResponse(originResponse, 401, 'Unauthorized', {
|
|
324
|
+
'WWW-Authenticate': 'Basic realm="Access to the proxy site", charset="UTF-8"'
|
|
175
325
|
});
|
|
326
|
+
this.failedRequests++;
|
|
327
|
+
return;
|
|
176
328
|
}
|
|
177
|
-
const authStringBase64 = authHeader.replace('Basic ', '');
|
|
178
|
-
const authString = plugins.smartstring.base64.decode(authStringBase64);
|
|
179
|
-
const userPassArray = authString.split(':');
|
|
180
|
-
const user = userPassArray[0];
|
|
181
|
-
const pass = userPassArray[1];
|
|
182
|
-
if (user === authInfo.user && pass === authInfo.pass) {
|
|
183
|
-
console.log('Request successfully authenticated');
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
return endOriginReqRes(403, 'Forbidden: Wrong credentials');
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
329
|
}
|
|
190
|
-
|
|
191
|
-
|
|
330
|
+
catch (error) {
|
|
331
|
+
this.log('error', `[${reqId}] Authentication error`, error);
|
|
332
|
+
this.sendErrorResponse(originResponse, 500, 'Internal Server Error: Authentication failed');
|
|
333
|
+
this.failedRequests++;
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Construct destination URL
|
|
338
|
+
const destinationUrl = `http://${destinationConfig.destinationIp}:${destinationConfig.destinationPort}${originRequest.url}`;
|
|
339
|
+
this.log('debug', `[${reqId}] Proxying to ${destinationUrl}`);
|
|
340
|
+
// Forward the request
|
|
341
|
+
await this.forwardRequest(reqId, originRequest, originResponse, destinationUrl);
|
|
342
|
+
const processingTime = Date.now() - startTime;
|
|
343
|
+
this.log('debug', `[${reqId}] Request completed in ${processingTime}ms`);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
this.log('error', `[${reqId}] Unhandled error in request handler`, error);
|
|
347
|
+
try {
|
|
348
|
+
this.sendErrorResponse(originResponse, 502, 'Bad Gateway: Server error');
|
|
349
|
+
}
|
|
350
|
+
catch (responseError) {
|
|
351
|
+
this.log('error', `[${reqId}] Failed to send error response`, responseError);
|
|
192
352
|
}
|
|
353
|
+
this.failedRequests++;
|
|
193
354
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Handles a CORS preflight request
|
|
358
|
+
*/
|
|
359
|
+
handleCorsRequest(req, res) {
|
|
360
|
+
const cors = this.options.cors;
|
|
361
|
+
// Set CORS headers
|
|
362
|
+
res.setHeader('Access-Control-Allow-Origin', cors.allowOrigin);
|
|
363
|
+
res.setHeader('Access-Control-Allow-Methods', cors.allowMethods);
|
|
364
|
+
res.setHeader('Access-Control-Allow-Headers', cors.allowHeaders);
|
|
365
|
+
res.setHeader('Access-Control-Max-Age', String(cors.maxAge));
|
|
366
|
+
// Handle preflight request
|
|
367
|
+
res.statusCode = 204;
|
|
368
|
+
res.end();
|
|
369
|
+
// Count this as a request served
|
|
370
|
+
this.requestsServed++;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Authenticates a request against the destination config
|
|
374
|
+
*/
|
|
375
|
+
authenticateRequest(req, config) {
|
|
376
|
+
const authInfo = config.authentication;
|
|
377
|
+
if (!authInfo) {
|
|
378
|
+
return true; // No authentication required
|
|
197
379
|
}
|
|
198
|
-
|
|
199
|
-
|
|
380
|
+
switch (authInfo.type) {
|
|
381
|
+
case 'Basic': {
|
|
382
|
+
const authHeader = req.headers.authorization;
|
|
383
|
+
if (!authHeader || !authHeader.includes('Basic ')) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
const authStringBase64 = authHeader.replace('Basic ', '');
|
|
387
|
+
const authString = plugins.smartstring.base64.decode(authStringBase64);
|
|
388
|
+
const [user, pass] = authString.split(':');
|
|
389
|
+
// Use constant-time comparison to prevent timing attacks
|
|
390
|
+
const userMatch = user === authInfo.user;
|
|
391
|
+
const passMatch = pass === authInfo.pass;
|
|
392
|
+
return userMatch && passMatch;
|
|
393
|
+
}
|
|
394
|
+
default:
|
|
395
|
+
throw new Error(`Unsupported authentication method: ${authInfo.type}`);
|
|
200
396
|
}
|
|
201
|
-
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Forwards a request to the destination
|
|
400
|
+
*/
|
|
401
|
+
async forwardRequest(reqId, originRequest, originResponse, destinationUrl) {
|
|
202
402
|
try {
|
|
203
|
-
const
|
|
403
|
+
const proxyRequest = await plugins.smartrequest.request(destinationUrl, {
|
|
204
404
|
method: originRequest.method,
|
|
205
|
-
headers:
|
|
206
|
-
...originRequest.headers,
|
|
207
|
-
'X-Forwarded-Host': originRequest.headers.host,
|
|
208
|
-
'X-Forwarded-Proto': 'https',
|
|
209
|
-
},
|
|
405
|
+
headers: this.prepareForwardHeaders(originRequest),
|
|
210
406
|
keepAlive: true,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
407
|
+
timeout: 30000 // 30 second timeout
|
|
408
|
+
}, true, // streaming
|
|
409
|
+
(proxyRequestStream) => this.setupRequestStreaming(originRequest, proxyRequestStream));
|
|
410
|
+
// Handle the response
|
|
411
|
+
this.processProxyResponse(reqId, originResponse, proxyRequest);
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
this.log('error', `[${reqId}] Error forwarding request`, error);
|
|
415
|
+
this.sendErrorResponse(originResponse, 502, 'Bad Gateway: Unable to reach upstream server');
|
|
416
|
+
throw error; // Let the main handler catch this
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Prepares headers to forward to the backend
|
|
421
|
+
*/
|
|
422
|
+
prepareForwardHeaders(req) {
|
|
423
|
+
const safeHeaders = { ...req.headers };
|
|
424
|
+
// Add forwarding headers
|
|
425
|
+
safeHeaders['X-Forwarded-Host'] = req.headers.host;
|
|
426
|
+
safeHeaders['X-Forwarded-Proto'] = 'https';
|
|
427
|
+
safeHeaders['X-Forwarded-For'] = (req.socket.remoteAddress || '').replace(/^::ffff:/, '');
|
|
428
|
+
// Add proxy-specific headers
|
|
429
|
+
safeHeaders['X-Proxy-Id'] = `NetworkProxy-${this.options.port}`;
|
|
430
|
+
// Remove sensitive headers we don't want to forward
|
|
431
|
+
const sensitiveHeaders = ['connection', 'upgrade', 'http2-settings'];
|
|
432
|
+
for (const header of sensitiveHeaders) {
|
|
433
|
+
delete safeHeaders[header];
|
|
434
|
+
}
|
|
435
|
+
return safeHeaders;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Sets up request streaming for the proxy
|
|
439
|
+
*/
|
|
440
|
+
setupRequestStreaming(originRequest, proxyRequest) {
|
|
441
|
+
// Forward request body data
|
|
442
|
+
originRequest.on('data', (chunk) => {
|
|
443
|
+
proxyRequest.write(chunk);
|
|
444
|
+
});
|
|
445
|
+
// End the request when done
|
|
446
|
+
originRequest.on('end', () => {
|
|
447
|
+
proxyRequest.end();
|
|
448
|
+
});
|
|
449
|
+
// Handle request errors
|
|
450
|
+
originRequest.on('error', (error) => {
|
|
451
|
+
this.log('error', 'Error in client request stream', error);
|
|
452
|
+
proxyRequest.destroy(error);
|
|
453
|
+
});
|
|
454
|
+
// Handle client abort/timeout
|
|
455
|
+
originRequest.on('close', () => {
|
|
456
|
+
if (!originRequest.complete) {
|
|
457
|
+
this.log('debug', 'Client closed connection before request completed');
|
|
458
|
+
proxyRequest.destroy();
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
originRequest.on('timeout', () => {
|
|
462
|
+
this.log('debug', 'Client request timeout');
|
|
463
|
+
proxyRequest.destroy(new Error('Client request timeout'));
|
|
464
|
+
});
|
|
465
|
+
// Handle proxy request errors
|
|
466
|
+
proxyRequest.on('error', (error) => {
|
|
467
|
+
this.log('error', 'Error in outgoing proxy request', error);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Processes a proxy response
|
|
472
|
+
*/
|
|
473
|
+
processProxyResponse(reqId, originResponse, proxyResponse) {
|
|
474
|
+
this.log('debug', `[${reqId}] Received upstream response: ${proxyResponse.statusCode}`);
|
|
475
|
+
// Set status code
|
|
476
|
+
originResponse.statusCode = proxyResponse.statusCode;
|
|
477
|
+
// Add default headers
|
|
478
|
+
for (const [headerName, headerValue] of Object.entries(this.defaultHeaders)) {
|
|
479
|
+
originResponse.setHeader(headerName, headerValue);
|
|
480
|
+
}
|
|
481
|
+
// Add CORS headers if enabled
|
|
482
|
+
if (this.options.cors) {
|
|
483
|
+
originResponse.setHeader('Access-Control-Allow-Origin', this.options.cors.allowOrigin);
|
|
484
|
+
}
|
|
485
|
+
// Copy response headers
|
|
486
|
+
for (const [headerName, headerValue] of Object.entries(proxyResponse.headers)) {
|
|
487
|
+
// Skip hop-by-hop headers
|
|
488
|
+
const hopByHopHeaders = ['connection', 'keep-alive', 'transfer-encoding', 'te',
|
|
489
|
+
'trailer', 'upgrade', 'proxy-authorization', 'proxy-authenticate'];
|
|
490
|
+
if (!hopByHopHeaders.includes(headerName.toLowerCase())) {
|
|
491
|
+
originResponse.setHeader(headerName, headerValue);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// Stream response body
|
|
495
|
+
proxyResponse.on('data', (chunk) => {
|
|
496
|
+
const canContinue = originResponse.write(chunk);
|
|
497
|
+
// Apply backpressure if needed
|
|
498
|
+
if (!canContinue) {
|
|
499
|
+
proxyResponse.pause();
|
|
500
|
+
originResponse.once('drain', () => {
|
|
501
|
+
proxyResponse.resume();
|
|
231
502
|
});
|
|
232
|
-
});
|
|
233
|
-
originResponse.statusCode = proxyResponse.statusCode;
|
|
234
|
-
console.log(proxyResponse.statusCode);
|
|
235
|
-
for (const defaultHeader of Object.keys(this.defaultHeaders)) {
|
|
236
|
-
originResponse.setHeader(defaultHeader, this.defaultHeaders[defaultHeader]);
|
|
237
503
|
}
|
|
238
|
-
|
|
239
|
-
|
|
504
|
+
});
|
|
505
|
+
// End the response when done
|
|
506
|
+
proxyResponse.on('end', () => {
|
|
507
|
+
originResponse.end();
|
|
508
|
+
});
|
|
509
|
+
// Handle response errors
|
|
510
|
+
proxyResponse.on('error', (error) => {
|
|
511
|
+
this.log('error', `[${reqId}] Error in proxy response stream`, error);
|
|
512
|
+
originResponse.destroy(error);
|
|
513
|
+
});
|
|
514
|
+
originResponse.on('error', (error) => {
|
|
515
|
+
this.log('error', `[${reqId}] Error in client response stream`, error);
|
|
516
|
+
proxyResponse.destroy();
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Sends an error response to the client
|
|
521
|
+
*/
|
|
522
|
+
sendErrorResponse(res, statusCode = 500, message = 'Internal Server Error', headers = {}) {
|
|
523
|
+
try {
|
|
524
|
+
// If headers already sent, just end the response
|
|
525
|
+
if (res.headersSent) {
|
|
526
|
+
res.end();
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
// Add default headers
|
|
530
|
+
for (const [key, value] of Object.entries(this.defaultHeaders)) {
|
|
531
|
+
res.setHeader(key, value);
|
|
532
|
+
}
|
|
533
|
+
// Add provided headers
|
|
534
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
535
|
+
res.setHeader(key, value);
|
|
536
|
+
}
|
|
537
|
+
// Send error response
|
|
538
|
+
res.writeHead(statusCode, message);
|
|
539
|
+
// Send error body as JSON for API clients
|
|
540
|
+
if (res.getHeader('Content-Type') === 'application/json') {
|
|
541
|
+
res.end(JSON.stringify({ error: { status: statusCode, message } }));
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
// Send as plain text
|
|
545
|
+
res.end(message);
|
|
240
546
|
}
|
|
241
|
-
proxyResponse.on('data', (data) => {
|
|
242
|
-
originResponse.write(data);
|
|
243
|
-
});
|
|
244
|
-
proxyResponse.on('end', () => {
|
|
245
|
-
originResponse.end();
|
|
246
|
-
});
|
|
247
|
-
proxyResponse.on('error', () => {
|
|
248
|
-
originResponse.destroy();
|
|
249
|
-
});
|
|
250
|
-
proxyResponse.on('close', () => {
|
|
251
|
-
originResponse.end();
|
|
252
|
-
});
|
|
253
|
-
proxyResponse.on('timeout', () => {
|
|
254
|
-
originResponse.end();
|
|
255
|
-
originResponse.destroy();
|
|
256
|
-
});
|
|
257
547
|
}
|
|
258
548
|
catch (error) {
|
|
259
|
-
|
|
260
|
-
|
|
549
|
+
this.log('error', 'Error sending error response', error);
|
|
550
|
+
try {
|
|
551
|
+
res.destroy();
|
|
552
|
+
}
|
|
553
|
+
catch (destroyError) {
|
|
554
|
+
// Last resort - nothing more we can do
|
|
555
|
+
}
|
|
261
556
|
}
|
|
262
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* Updates proxy configurations
|
|
560
|
+
*/
|
|
263
561
|
async updateProxyConfigs(proxyConfigsArg) {
|
|
264
|
-
|
|
562
|
+
this.log('info', `Updating proxy configurations (${proxyConfigsArg.length} configs)`);
|
|
563
|
+
// Update internal configs
|
|
265
564
|
this.proxyConfigs = proxyConfigsArg;
|
|
266
565
|
this.router.setNewProxyConfigs(proxyConfigsArg);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
566
|
+
// Collect all hostnames for cleanup later
|
|
567
|
+
const currentHostNames = new Set();
|
|
568
|
+
// Add/update SSL contexts for each host
|
|
569
|
+
for (const config of proxyConfigsArg) {
|
|
570
|
+
currentHostNames.add(config.hostName);
|
|
571
|
+
try {
|
|
572
|
+
// Check if we need to update the cert
|
|
573
|
+
const currentCert = this.certificateCache.get(config.hostName);
|
|
574
|
+
const shouldUpdate = !currentCert ||
|
|
575
|
+
currentCert.key !== config.privateKey ||
|
|
576
|
+
currentCert.cert !== config.publicKey;
|
|
577
|
+
if (shouldUpdate) {
|
|
578
|
+
this.log('debug', `Updating SSL context for ${config.hostName}`);
|
|
579
|
+
// Update the HTTPS server context
|
|
580
|
+
this.httpsServer.addContext(config.hostName, {
|
|
581
|
+
key: config.privateKey,
|
|
582
|
+
cert: config.publicKey
|
|
583
|
+
});
|
|
584
|
+
// Update the cache
|
|
585
|
+
this.certificateCache.set(config.hostName, {
|
|
586
|
+
key: config.privateKey,
|
|
587
|
+
cert: config.publicKey
|
|
588
|
+
});
|
|
589
|
+
this.activeContexts.add(config.hostName);
|
|
279
590
|
}
|
|
280
591
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
592
|
+
catch (error) {
|
|
593
|
+
this.log('error', `Failed to add SSL context for ${config.hostName}`, error);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
// Clean up removed contexts
|
|
597
|
+
// Note: Node.js doesn't officially support removing contexts
|
|
598
|
+
// This would require server restart in production
|
|
599
|
+
for (const hostname of this.activeContexts) {
|
|
600
|
+
if (!currentHostNames.has(hostname)) {
|
|
601
|
+
this.log('info', `Hostname ${hostname} removed from configuration`);
|
|
602
|
+
this.activeContexts.delete(hostname);
|
|
603
|
+
this.certificateCache.delete(hostname);
|
|
604
|
+
}
|
|
285
605
|
}
|
|
286
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Adds default headers to be included in all responses
|
|
609
|
+
*/
|
|
287
610
|
async addDefaultHeaders(headersArg) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
611
|
+
this.log('info', 'Adding default headers', headersArg);
|
|
612
|
+
this.defaultHeaders = {
|
|
613
|
+
...this.defaultHeaders,
|
|
614
|
+
...headersArg
|
|
615
|
+
};
|
|
291
616
|
}
|
|
617
|
+
/**
|
|
618
|
+
* Stops the proxy server
|
|
619
|
+
*/
|
|
292
620
|
async stop() {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
621
|
+
this.log('info', 'Stopping NetworkProxy server');
|
|
622
|
+
// Clear intervals
|
|
623
|
+
if (this.heartbeatInterval) {
|
|
624
|
+
clearInterval(this.heartbeatInterval);
|
|
625
|
+
}
|
|
626
|
+
if (this.metricsInterval) {
|
|
627
|
+
clearInterval(this.metricsInterval);
|
|
628
|
+
}
|
|
629
|
+
// Close WebSocket server if exists
|
|
630
|
+
if (this.wsServer) {
|
|
631
|
+
for (const client of this.wsServer.clients) {
|
|
632
|
+
try {
|
|
633
|
+
client.terminate();
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
this.log('error', 'Error terminating WebSocket client', error);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
// Close all tracked sockets
|
|
297
641
|
for (const socket of this.socketMap.getArray()) {
|
|
298
|
-
|
|
642
|
+
try {
|
|
643
|
+
socket.destroy();
|
|
644
|
+
}
|
|
645
|
+
catch (error) {
|
|
646
|
+
this.log('error', 'Error destroying socket', error);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
// Close the HTTPS server
|
|
650
|
+
return new Promise((resolve) => {
|
|
651
|
+
this.httpsServer.close(() => {
|
|
652
|
+
this.log('info', 'NetworkProxy server stopped successfully');
|
|
653
|
+
resolve();
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Logs a message according to the configured log level
|
|
659
|
+
*/
|
|
660
|
+
log(level, message, data) {
|
|
661
|
+
const logLevels = {
|
|
662
|
+
error: 0,
|
|
663
|
+
warn: 1,
|
|
664
|
+
info: 2,
|
|
665
|
+
debug: 3
|
|
666
|
+
};
|
|
667
|
+
// Skip if log level is higher than configured
|
|
668
|
+
if (logLevels[level] > logLevels[this.options.logLevel]) {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const timestamp = new Date().toISOString();
|
|
672
|
+
const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
|
|
673
|
+
switch (level) {
|
|
674
|
+
case 'error':
|
|
675
|
+
console.error(`${prefix} ${message}`, data || '');
|
|
676
|
+
break;
|
|
677
|
+
case 'warn':
|
|
678
|
+
console.warn(`${prefix} ${message}`, data || '');
|
|
679
|
+
break;
|
|
680
|
+
case 'info':
|
|
681
|
+
console.log(`${prefix} ${message}`, data || '');
|
|
682
|
+
break;
|
|
683
|
+
case 'debug':
|
|
684
|
+
console.log(`${prefix} ${message}`, data || '');
|
|
685
|
+
break;
|
|
299
686
|
}
|
|
300
|
-
await done.promise;
|
|
301
|
-
clearInterval(this.heartbeatInterval);
|
|
302
|
-
console.log('NetworkProxy -> OK: Server has been stopped and all connections closed.');
|
|
303
687
|
}
|
|
304
688
|
}
|
|
305
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5uZXR3b3JrcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm5ldHdvcmtwcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEQsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQVVwQyxNQUFNLE9BQU8sWUFBWTtJQWN2QixZQUFZLFVBQWdDO1FBWnJDLGlCQUFZLEdBQWtELEVBQUUsQ0FBQztRQUVqRSxXQUFNLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUMzQixjQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBc0IsQ0FBQztRQUM1RCxtQkFBYyxHQUE4QixFQUFFLENBQUM7UUFJL0MsK0JBQTBCLEdBRTdCLEVBQUUsQ0FBQztRQUdMLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMvRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRS9ELElBQUksQ0FBQztZQUNILElBQUksQ0FBQyxtQkFBbUIsR0FBRztnQkFDekIsR0FBRyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLEVBQUUsTUFBTSxDQUFDO2dCQUM1RCxJQUFJLEVBQUUs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
|
|
689
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5uZXR3b3JrcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm5ldHdvcmtwcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEQsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQXFCcEMsTUFBTSxPQUFPLFlBQVk7SUEyQnZCOztPQUVHO0lBQ0gsWUFBWSxVQUFnQztRQTNCckMsaUJBQVksR0FBa0QsRUFBRSxDQUFDO1FBQ2pFLG1CQUFjLEdBQThCLEVBQUUsQ0FBQztRQU10RCxpQkFBaUI7UUFDVixXQUFNLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUMzQixjQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBc0IsQ0FBQztRQUM1RCxtQkFBYyxHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLHFCQUFnQixHQUFXLENBQUMsQ0FBQztRQUM3QixjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBQ3RCLG1CQUFjLEdBQVcsQ0FBQyxDQUFDO1FBQzNCLG1CQUFjLEdBQVcsQ0FBQyxDQUFDO1FBUTFCLHFCQUFnQixHQUErRCxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBTS9GLHNCQUFzQjtRQUN0QixJQUFJLENBQUMsT0FBTyxHQUFHO1lBQ2IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO1lBQ3JCLGNBQWMsRUFBRSxVQUFVLENBQUMsY0FBYyxJQUFJLEtBQUs7WUFDbEQsZ0JBQWdCLEVBQUUsVUFBVSxDQUFDLGdCQUFnQixJQUFJLE1BQU0sRUFBRSxhQUFhO1lBQ3RFLGNBQWMsRUFBRSxV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
|