@zimic/interceptor 0.17.0-canary.1 → 0.17.0-canary.3
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/{chunk-3SKHNQLL.mjs → chunk-L75WKVZO.mjs} +508 -60
- package/dist/chunk-L75WKVZO.mjs.map +1 -0
- package/dist/{chunk-TYHJPU5G.js → chunk-PURXNE6R.js} +519 -61
- package/dist/chunk-PURXNE6R.js.map +1 -0
- package/dist/cli.js +141 -17
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +137 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/http.d.ts +14 -0
- package/dist/http.js +449 -269
- package/dist/http.js.map +1 -1
- package/dist/http.mjs +449 -269
- package/dist/http.mjs.map +1 -1
- package/dist/scripts/postinstall.js +6 -6
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/postinstall.mjs +5 -5
- package/dist/scripts/postinstall.mjs.map +1 -1
- package/dist/server.d.ts +16 -0
- package/dist/server.js +6 -6
- package/dist/server.mjs +1 -1
- package/package.json +11 -10
- package/src/cli/browser/init.ts +5 -6
- package/src/cli/cli.ts +140 -55
- package/src/cli/server/start.ts +22 -7
- package/src/cli/server/token/create.ts +33 -0
- package/src/cli/server/token/list.ts +23 -0
- package/src/cli/server/token/remove.ts +22 -0
- package/src/http/interceptor/HttpInterceptorClient.ts +49 -27
- package/src/http/interceptor/HttpInterceptorStore.ts +25 -9
- package/src/http/interceptor/LocalHttpInterceptor.ts +6 -3
- package/src/http/interceptor/RemoteHttpInterceptor.ts +9 -4
- package/src/http/interceptor/types/options.ts +15 -0
- package/src/http/interceptorWorker/HttpInterceptorWorker.ts +14 -16
- package/src/http/interceptorWorker/RemoteHttpInterceptorWorker.ts +17 -12
- package/src/http/interceptorWorker/types/options.ts +1 -0
- package/src/http/requestHandler/errors/TimesCheckError.ts +1 -1
- package/src/server/InterceptorServer.ts +52 -8
- package/src/server/constants.ts +1 -1
- package/src/server/errors/InvalidInterceptorTokenError.ts +13 -0
- package/src/server/errors/InvalidInterceptorTokenFileError.ts +13 -0
- package/src/server/errors/InvalidInterceptorTokenValueError.ts +13 -0
- package/src/server/types/options.ts +9 -0
- package/src/server/types/public.ts +9 -0
- package/src/server/types/schema.ts +4 -4
- package/src/server/utils/auth.ts +301 -0
- package/src/server/utils/fetch.ts +3 -1
- package/src/utils/data.ts +13 -0
- package/src/utils/files.ts +14 -0
- package/src/utils/{console.ts → logging.ts} +5 -7
- package/src/utils/webSocket.ts +57 -11
- package/src/webSocket/WebSocketClient.ts +11 -5
- package/src/webSocket/WebSocketHandler.ts +72 -51
- package/src/webSocket/WebSocketServer.ts +25 -4
- package/src/webSocket/constants.ts +2 -0
- package/src/webSocket/errors/UnauthorizedWebSocketConnectionError.ts +11 -0
- package/src/webSocket/types.ts +49 -52
- package/dist/chunk-3SKHNQLL.mjs.map +0 -1
- package/dist/chunk-TYHJPU5G.js.map +0 -1
|
@@ -4,13 +4,24 @@ var chunkWCQVDF3K_js = require('./chunk-WCQVDF3K.js');
|
|
|
4
4
|
var http = require('@zimic/http');
|
|
5
5
|
var server = require('@whatwg-node/server');
|
|
6
6
|
var http$1 = require('http');
|
|
7
|
-
var
|
|
7
|
+
var color3 = require('picocolors');
|
|
8
8
|
var ClientSocket = require('isomorphic-ws');
|
|
9
|
+
var crypto = require('crypto');
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
var os = require('os');
|
|
12
|
+
var path = require('path');
|
|
13
|
+
var util = require('util');
|
|
14
|
+
var zod = require('zod');
|
|
9
15
|
|
|
10
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
17
|
|
|
12
|
-
var
|
|
18
|
+
var color3__default = /*#__PURE__*/_interopDefault(color3);
|
|
13
19
|
var ClientSocket__default = /*#__PURE__*/_interopDefault(ClientSocket);
|
|
20
|
+
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
21
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
22
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
23
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
24
|
+
var util__default = /*#__PURE__*/_interopDefault(util);
|
|
14
25
|
|
|
15
26
|
// src/server/errors/RunningInterceptorServerError.ts
|
|
16
27
|
var RunningInterceptorServerError = class extends Error {
|
|
@@ -119,6 +130,19 @@ function methodCanHaveResponseBody(method) {
|
|
|
119
130
|
}
|
|
120
131
|
chunkWCQVDF3K_js.__name(methodCanHaveResponseBody, "methodCanHaveResponseBody");
|
|
121
132
|
|
|
133
|
+
// src/webSocket/errors/UnauthorizedWebSocketConnectionError.ts
|
|
134
|
+
var UnauthorizedWebSocketConnectionError = class extends Error {
|
|
135
|
+
constructor(event) {
|
|
136
|
+
super(`${event.reason} (code ${event.code})`);
|
|
137
|
+
this.event = event;
|
|
138
|
+
this.name = "UnauthorizedWebSocketConnectionError";
|
|
139
|
+
}
|
|
140
|
+
static {
|
|
141
|
+
chunkWCQVDF3K_js.__name(this, "UnauthorizedWebSocketConnectionError");
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
var UnauthorizedWebSocketConnectionError_default = UnauthorizedWebSocketConnectionError;
|
|
145
|
+
|
|
122
146
|
// src/utils/webSocket.ts
|
|
123
147
|
var WebSocketTimeoutError = class extends Error {
|
|
124
148
|
static {
|
|
@@ -164,29 +188,58 @@ var WebSocketCloseTimeoutError = class extends WebSocketTimeoutError {
|
|
|
164
188
|
var DEFAULT_WEB_SOCKET_LIFECYCLE_TIMEOUT = 60 * 1e3;
|
|
165
189
|
var DEFAULT_WEB_SOCKET_MESSAGE_TIMEOUT = 3 * 60 * 1e3;
|
|
166
190
|
async function waitForOpenClientSocket(socket, options = {}) {
|
|
167
|
-
const { timeout: timeoutDuration = DEFAULT_WEB_SOCKET_LIFECYCLE_TIMEOUT } = options;
|
|
191
|
+
const { timeout: timeoutDuration = DEFAULT_WEB_SOCKET_LIFECYCLE_TIMEOUT, waitForAuthentication = false } = options;
|
|
168
192
|
const isAlreadyOpen = socket.readyState === socket.OPEN;
|
|
169
193
|
if (isAlreadyOpen) {
|
|
170
194
|
return;
|
|
171
195
|
}
|
|
172
196
|
await new Promise((resolve, reject) => {
|
|
173
|
-
function
|
|
197
|
+
function removeAllSocketListeners() {
|
|
198
|
+
socket.removeEventListener("message", handleSocketMessage);
|
|
174
199
|
socket.removeEventListener("open", handleOpenSuccess);
|
|
200
|
+
socket.removeEventListener("error", handleOpenError);
|
|
201
|
+
socket.removeEventListener("close", handleClose);
|
|
202
|
+
}
|
|
203
|
+
chunkWCQVDF3K_js.__name(removeAllSocketListeners, "removeAllSocketListeners");
|
|
204
|
+
function handleOpenError(error) {
|
|
205
|
+
removeAllSocketListeners();
|
|
175
206
|
reject(error);
|
|
176
207
|
}
|
|
177
208
|
chunkWCQVDF3K_js.__name(handleOpenError, "handleOpenError");
|
|
209
|
+
function handleClose(event) {
|
|
210
|
+
const isUnauthorized = event.code === 1008;
|
|
211
|
+
if (isUnauthorized) {
|
|
212
|
+
const unauthorizedError = new UnauthorizedWebSocketConnectionError_default(event);
|
|
213
|
+
handleOpenError(unauthorizedError);
|
|
214
|
+
} else {
|
|
215
|
+
handleOpenError(event);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
chunkWCQVDF3K_js.__name(handleClose, "handleClose");
|
|
178
219
|
const openTimeout = setTimeout(() => {
|
|
179
220
|
const timeoutError = new WebSocketOpenTimeoutError(timeoutDuration);
|
|
180
221
|
handleOpenError(timeoutError);
|
|
181
222
|
}, timeoutDuration);
|
|
182
223
|
function handleOpenSuccess() {
|
|
183
|
-
|
|
224
|
+
removeAllSocketListeners();
|
|
184
225
|
clearTimeout(openTimeout);
|
|
185
226
|
resolve();
|
|
186
227
|
}
|
|
187
228
|
chunkWCQVDF3K_js.__name(handleOpenSuccess, "handleOpenSuccess");
|
|
188
|
-
|
|
229
|
+
function handleSocketMessage(message) {
|
|
230
|
+
const hasValidAuth = message.data === "socket:auth:valid";
|
|
231
|
+
if (hasValidAuth) {
|
|
232
|
+
handleOpenSuccess();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
chunkWCQVDF3K_js.__name(handleSocketMessage, "handleSocketMessage");
|
|
236
|
+
if (waitForAuthentication) {
|
|
237
|
+
socket.addEventListener("message", handleSocketMessage);
|
|
238
|
+
} else {
|
|
239
|
+
socket.addEventListener("open", handleOpenSuccess);
|
|
240
|
+
}
|
|
189
241
|
socket.addEventListener("error", handleOpenError);
|
|
242
|
+
socket.addEventListener("close", handleClose);
|
|
190
243
|
});
|
|
191
244
|
}
|
|
192
245
|
chunkWCQVDF3K_js.__name(waitForOpenClientSocket, "waitForOpenClientSocket");
|
|
@@ -197,23 +250,28 @@ async function closeClientSocket(socket, options = {}) {
|
|
|
197
250
|
return;
|
|
198
251
|
}
|
|
199
252
|
await new Promise((resolve, reject) => {
|
|
200
|
-
function
|
|
201
|
-
socket.removeEventListener("
|
|
253
|
+
function removeAllSocketListeners() {
|
|
254
|
+
socket.removeEventListener("error", handleError);
|
|
255
|
+
socket.removeEventListener("close", handleClose);
|
|
256
|
+
}
|
|
257
|
+
chunkWCQVDF3K_js.__name(removeAllSocketListeners, "removeAllSocketListeners");
|
|
258
|
+
function handleError(error) {
|
|
259
|
+
removeAllSocketListeners();
|
|
202
260
|
reject(error);
|
|
203
261
|
}
|
|
204
|
-
chunkWCQVDF3K_js.__name(
|
|
262
|
+
chunkWCQVDF3K_js.__name(handleError, "handleError");
|
|
205
263
|
const closeTimeout = setTimeout(() => {
|
|
206
264
|
const timeoutError = new WebSocketCloseTimeoutError(timeoutDuration);
|
|
207
|
-
|
|
265
|
+
handleError(timeoutError);
|
|
208
266
|
}, timeoutDuration);
|
|
209
|
-
function
|
|
210
|
-
|
|
267
|
+
function handleClose() {
|
|
268
|
+
removeAllSocketListeners();
|
|
211
269
|
clearTimeout(closeTimeout);
|
|
212
270
|
resolve();
|
|
213
271
|
}
|
|
214
|
-
chunkWCQVDF3K_js.__name(
|
|
215
|
-
socket.addEventListener("error",
|
|
216
|
-
socket.addEventListener("close",
|
|
272
|
+
chunkWCQVDF3K_js.__name(handleClose, "handleClose");
|
|
273
|
+
socket.addEventListener("error", handleError);
|
|
274
|
+
socket.addEventListener("close", handleClose);
|
|
217
275
|
socket.close();
|
|
218
276
|
});
|
|
219
277
|
}
|
|
@@ -302,6 +360,12 @@ function removeArrayElement(array, element) {
|
|
|
302
360
|
}
|
|
303
361
|
chunkWCQVDF3K_js.__name(removeArrayElement, "removeArrayElement");
|
|
304
362
|
|
|
363
|
+
// src/utils/environment.ts
|
|
364
|
+
function isClientSide() {
|
|
365
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
366
|
+
}
|
|
367
|
+
chunkWCQVDF3K_js.__name(isClientSide, "isClientSide");
|
|
368
|
+
|
|
305
369
|
// ../zimic-utils/dist/import/createCachedDynamicImport.mjs
|
|
306
370
|
function createCachedDynamicImport(importModuleDynamically) {
|
|
307
371
|
let cachedImportResult;
|
|
@@ -314,11 +378,87 @@ chunkWCQVDF3K_js.__name(createCachedDynamicImport, "createCachedDynamicImport");
|
|
|
314
378
|
__name2(createCachedDynamicImport, "createCachedDynamicImport");
|
|
315
379
|
var createCachedDynamicImport_default = createCachedDynamicImport;
|
|
316
380
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
381
|
+
// ../zimic-utils/dist/logging/Logger.mjs
|
|
382
|
+
var Logger = class _Logger {
|
|
383
|
+
static {
|
|
384
|
+
chunkWCQVDF3K_js.__name(this, "_Logger");
|
|
385
|
+
}
|
|
386
|
+
static {
|
|
387
|
+
__name2(this, "Logger");
|
|
388
|
+
}
|
|
389
|
+
prefix;
|
|
390
|
+
raw;
|
|
391
|
+
constructor(options = {}) {
|
|
392
|
+
const { prefix } = options;
|
|
393
|
+
this.prefix = prefix;
|
|
394
|
+
this.raw = prefix ? new _Logger({ ...options, prefix: void 0 }) : this;
|
|
395
|
+
}
|
|
396
|
+
logWithLevel(level, ...messages) {
|
|
397
|
+
if (this.prefix) {
|
|
398
|
+
console[level](this.prefix, ...messages);
|
|
399
|
+
} else {
|
|
400
|
+
console[level](...messages);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
info(...messages) {
|
|
404
|
+
this.logWithLevel("log", ...messages);
|
|
405
|
+
}
|
|
406
|
+
warn(...messages) {
|
|
407
|
+
this.logWithLevel("warn", ...messages);
|
|
408
|
+
}
|
|
409
|
+
error(...messages) {
|
|
410
|
+
this.logWithLevel("error", ...messages);
|
|
411
|
+
}
|
|
412
|
+
table(headers, rows) {
|
|
413
|
+
const columnLengths = headers.map((header) => {
|
|
414
|
+
let maxValueLength = header.title.length;
|
|
415
|
+
for (const row of rows) {
|
|
416
|
+
const value = row[header.property];
|
|
417
|
+
if (value.length > maxValueLength) {
|
|
418
|
+
maxValueLength = value.length;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return maxValueLength;
|
|
422
|
+
});
|
|
423
|
+
const formattedRows = [];
|
|
424
|
+
const horizontalLine = columnLengths.map((length) => "\u2500".repeat(length));
|
|
425
|
+
formattedRows.push(horizontalLine, []);
|
|
426
|
+
for (let headerIndex = 0; headerIndex < headers.length; headerIndex++) {
|
|
427
|
+
const header = headers[headerIndex];
|
|
428
|
+
const columnLength = columnLengths[headerIndex];
|
|
429
|
+
const value = header.title;
|
|
430
|
+
formattedRows.at(-1)?.push(value.padEnd(columnLength, " "));
|
|
431
|
+
}
|
|
432
|
+
formattedRows.push(horizontalLine);
|
|
433
|
+
for (const row of rows) {
|
|
434
|
+
formattedRows.push([]);
|
|
435
|
+
for (let headerIndex = 0; headerIndex < headers.length; headerIndex++) {
|
|
436
|
+
const header = headers[headerIndex];
|
|
437
|
+
const columnLength = columnLengths[headerIndex];
|
|
438
|
+
const value = row[header.property];
|
|
439
|
+
formattedRows.at(-1)?.push(value.padEnd(columnLength, " "));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
formattedRows.push(horizontalLine);
|
|
443
|
+
const formattedTable = formattedRows.map((row, index) => {
|
|
444
|
+
const isFirstLine = index === 0;
|
|
445
|
+
if (isFirstLine) {
|
|
446
|
+
return `\u250C\u2500${row.join("\u2500\u252C\u2500")}\u2500\u2510`;
|
|
447
|
+
}
|
|
448
|
+
const isLineAfterHeaders = index === 2;
|
|
449
|
+
if (isLineAfterHeaders) {
|
|
450
|
+
return `\u251C\u2500${row.join("\u2500\u253C\u2500")}\u2500\u2524`;
|
|
451
|
+
}
|
|
452
|
+
const isLastLine = index === formattedRows.length - 1;
|
|
453
|
+
if (isLastLine) {
|
|
454
|
+
return `\u2514\u2500${row.join("\u2500\u2534\u2500")}\u2500\u2518`;
|
|
455
|
+
}
|
|
456
|
+
return `\u2502 ${row.join(" \u2502 ")} \u2502`;
|
|
457
|
+
}).join("\n");
|
|
458
|
+
this.logWithLevel("log", formattedTable);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
var Logger_default = Logger;
|
|
322
462
|
|
|
323
463
|
// src/utils/files.ts
|
|
324
464
|
var importFile = createCachedDynamicImport_default(
|
|
@@ -327,16 +467,30 @@ var importFile = createCachedDynamicImport_default(
|
|
|
327
467
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
328
468
|
async () => globalThis.File ?? (await import('buffer')).File
|
|
329
469
|
);
|
|
470
|
+
var importFilesystem = createCachedDynamicImport_default(() => import('fs'));
|
|
471
|
+
async function pathExists(path2) {
|
|
472
|
+
const fs2 = await importFilesystem();
|
|
473
|
+
try {
|
|
474
|
+
await fs2.promises.access(path2);
|
|
475
|
+
return true;
|
|
476
|
+
} catch {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
chunkWCQVDF3K_js.__name(pathExists, "pathExists");
|
|
330
481
|
|
|
331
|
-
// src/utils/
|
|
482
|
+
// src/utils/logging.ts
|
|
483
|
+
var logger = new Logger_default({
|
|
484
|
+
prefix: color3__default.default.cyan("[@zimic/interceptor]")
|
|
485
|
+
});
|
|
332
486
|
var importUtil = createCachedDynamicImport_default(() => import('util'));
|
|
333
487
|
async function formatValueToLog(value, options = {}) {
|
|
334
488
|
if (isClientSide()) {
|
|
335
489
|
return value;
|
|
336
490
|
}
|
|
337
491
|
const { colors = true } = options;
|
|
338
|
-
const
|
|
339
|
-
return
|
|
492
|
+
const util2 = await importUtil();
|
|
493
|
+
return util2.inspect(value, {
|
|
340
494
|
colors,
|
|
341
495
|
compact: true,
|
|
342
496
|
depth: Infinity,
|
|
@@ -347,12 +501,6 @@ async function formatValueToLog(value, options = {}) {
|
|
|
347
501
|
});
|
|
348
502
|
}
|
|
349
503
|
chunkWCQVDF3K_js.__name(formatValueToLog, "formatValueToLog");
|
|
350
|
-
function logWithPrefix(messageOrMessages, options = {}) {
|
|
351
|
-
const { method = "log" } = options;
|
|
352
|
-
const messages = Array.isArray(messageOrMessages) ? messageOrMessages : [messageOrMessages];
|
|
353
|
-
console[method](color2__default.default.cyan("[@zimic/interceptor]"), ...messages);
|
|
354
|
-
}
|
|
355
|
-
chunkWCQVDF3K_js.__name(logWithPrefix, "logWithPrefix");
|
|
356
504
|
|
|
357
505
|
// src/http/requestHandler/types/requests.ts
|
|
358
506
|
var HTTP_INTERCEPTOR_REQUEST_HIDDEN_PROPERTIES = Object.freeze(
|
|
@@ -712,21 +860,18 @@ var HttpInterceptorWorker = class _HttpInterceptorWorker {
|
|
|
712
860
|
formatValueToLog(request.searchParams.toObject()),
|
|
713
861
|
formatValueToLog(request.body)
|
|
714
862
|
]);
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
`${action === "bypass" ? "Warning:" : "Error:"} Request was not handled and was ${action === "bypass" ? color2__default.default.yellow("bypassed") : color2__default.default.red("rejected")}.
|
|
863
|
+
logger[action === "bypass" ? "warn" : "error"](
|
|
864
|
+
`${action === "bypass" ? "Warning:" : "Error:"} Request was not handled and was ${action === "bypass" ? color3__default.default.yellow("bypassed") : color3__default.default.red("rejected")}.
|
|
718
865
|
|
|
719
866
|
`,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
],
|
|
729
|
-
{ method: action === "bypass" ? "warn" : "error" }
|
|
867
|
+
`${request.method} ${request.url}`,
|
|
868
|
+
"\n Headers:",
|
|
869
|
+
formattedHeaders,
|
|
870
|
+
"\n Search params:",
|
|
871
|
+
formattedSearchParams,
|
|
872
|
+
"\n Body:",
|
|
873
|
+
formattedBody,
|
|
874
|
+
"\n\nLearn more: https://github.com/zimicjs/zimic/wiki/api\u2010zimic\u2010interceptor\u2010http#unhandled-requests"
|
|
730
875
|
);
|
|
731
876
|
}
|
|
732
877
|
};
|
|
@@ -758,6 +903,17 @@ function convertBase64ToArrayBuffer(base64Value) {
|
|
|
758
903
|
}
|
|
759
904
|
}
|
|
760
905
|
chunkWCQVDF3K_js.__name(convertBase64ToArrayBuffer, "convertBase64ToArrayBuffer");
|
|
906
|
+
var HEX_REGEX = /^[a-z0-9]+$/;
|
|
907
|
+
function convertHexLengthToByteLength(hexLength) {
|
|
908
|
+
return Math.ceil(hexLength / 2);
|
|
909
|
+
}
|
|
910
|
+
chunkWCQVDF3K_js.__name(convertHexLengthToByteLength, "convertHexLengthToByteLength");
|
|
911
|
+
var BASE64URL_REGEX = /^[a-zA-Z0-9-_]+$/;
|
|
912
|
+
function convertHexLengthToBase64urlLength(hexLength) {
|
|
913
|
+
const byteLength = convertHexLengthToByteLength(hexLength);
|
|
914
|
+
return Math.ceil(byteLength * 4 / 3);
|
|
915
|
+
}
|
|
916
|
+
chunkWCQVDF3K_js.__name(convertHexLengthToBase64urlLength, "convertHexLengthToBase64urlLength");
|
|
761
917
|
|
|
762
918
|
// src/utils/fetch.ts
|
|
763
919
|
async function serializeRequest(request) {
|
|
@@ -795,6 +951,9 @@ var importCrypto = createCachedDynamicImport_default(async () => {
|
|
|
795
951
|
return globalCrypto ?? await import('crypto');
|
|
796
952
|
});
|
|
797
953
|
|
|
954
|
+
// src/webSocket/constants.ts
|
|
955
|
+
var WEB_SOCKET_CONTROL_MESSAGES = Object.freeze(["socket:auth:valid"]);
|
|
956
|
+
|
|
798
957
|
// src/webSocket/errors/InvalidWebSocketMessage.ts
|
|
799
958
|
var InvalidWebSocketMessage = class extends Error {
|
|
800
959
|
static {
|
|
@@ -835,8 +994,11 @@ var WebSocketHandler = class {
|
|
|
835
994
|
this.socketTimeout = options.socketTimeout ?? DEFAULT_WEB_SOCKET_LIFECYCLE_TIMEOUT;
|
|
836
995
|
this.messageTimeout = options.messageTimeout ?? DEFAULT_WEB_SOCKET_MESSAGE_TIMEOUT;
|
|
837
996
|
}
|
|
838
|
-
async registerSocket(socket) {
|
|
839
|
-
const openPromise = waitForOpenClientSocket(socket, {
|
|
997
|
+
async registerSocket(socket, options = {}) {
|
|
998
|
+
const openPromise = waitForOpenClientSocket(socket, {
|
|
999
|
+
timeout: this.socketTimeout,
|
|
1000
|
+
waitForAuthentication: options.waitForAuthentication
|
|
1001
|
+
});
|
|
840
1002
|
const handleSocketMessage = /* @__PURE__ */ chunkWCQVDF3K_js.__name(async (rawMessage) => {
|
|
841
1003
|
await this.handleSocketMessage(socket, rawMessage);
|
|
842
1004
|
}, "handleSocketMessage");
|
|
@@ -849,8 +1011,8 @@ var WebSocketHandler = class {
|
|
|
849
1011
|
socket.addEventListener("error", handleSocketError);
|
|
850
1012
|
const handleSocketClose = /* @__PURE__ */ chunkWCQVDF3K_js.__name(() => {
|
|
851
1013
|
socket.removeEventListener("message", handleSocketMessage);
|
|
852
|
-
socket.removeEventListener("error", handleSocketError);
|
|
853
1014
|
socket.removeEventListener("close", handleSocketClose);
|
|
1015
|
+
socket.removeEventListener("error", handleSocketError);
|
|
854
1016
|
this.removeSocket(socket);
|
|
855
1017
|
}, "handleSocketClose");
|
|
856
1018
|
socket.addEventListener("close", handleSocketClose);
|
|
@@ -858,6 +1020,9 @@ var WebSocketHandler = class {
|
|
|
858
1020
|
}
|
|
859
1021
|
handleSocketMessage = /* @__PURE__ */ chunkWCQVDF3K_js.__name(async (socket, rawMessage) => {
|
|
860
1022
|
try {
|
|
1023
|
+
if (this.isControlMessageData(rawMessage.data)) {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
861
1026
|
const stringifiedMessageData = this.readRawMessageData(rawMessage.data);
|
|
862
1027
|
const parsedMessageData = this.parseMessage(stringifiedMessageData);
|
|
863
1028
|
await this.notifyListeners(parsedMessageData, socket);
|
|
@@ -865,6 +1030,9 @@ var WebSocketHandler = class {
|
|
|
865
1030
|
console.error(error);
|
|
866
1031
|
}
|
|
867
1032
|
}, "handleSocketMessage");
|
|
1033
|
+
isControlMessageData(messageData) {
|
|
1034
|
+
return typeof messageData === "string" && WEB_SOCKET_CONTROL_MESSAGES.includes(messageData);
|
|
1035
|
+
}
|
|
868
1036
|
readRawMessageData(data) {
|
|
869
1037
|
if (typeof data === "string") {
|
|
870
1038
|
return data;
|
|
@@ -879,7 +1047,7 @@ var WebSocketHandler = class {
|
|
|
879
1047
|
} catch {
|
|
880
1048
|
throw new InvalidWebSocketMessage_default(stringifiedMessage);
|
|
881
1049
|
}
|
|
882
|
-
if (!this.
|
|
1050
|
+
if (!this.isMessage(parsedMessage)) {
|
|
883
1051
|
throw new InvalidWebSocketMessage_default(stringifiedMessage);
|
|
884
1052
|
}
|
|
885
1053
|
if (this.isReplyMessage(parsedMessage)) {
|
|
@@ -896,7 +1064,7 @@ var WebSocketHandler = class {
|
|
|
896
1064
|
data: parsedMessage.data
|
|
897
1065
|
};
|
|
898
1066
|
}
|
|
899
|
-
|
|
1067
|
+
isMessage(message) {
|
|
900
1068
|
return typeof message === "object" && message !== null && "id" in message && typeof message.id === "string" && "channel" in message && typeof message.channel === "string" && (!("requestId" in message) || typeof message.requestId === "string");
|
|
901
1069
|
}
|
|
902
1070
|
async notifyListeners(message, socket) {
|
|
@@ -932,9 +1100,9 @@ var WebSocketHandler = class {
|
|
|
932
1100
|
this.sockets.delete(socket);
|
|
933
1101
|
}
|
|
934
1102
|
async createEventMessage(channel, eventData) {
|
|
935
|
-
const
|
|
1103
|
+
const crypto2 = await importCrypto();
|
|
936
1104
|
const eventMessage = {
|
|
937
|
-
id:
|
|
1105
|
+
id: crypto2.randomUUID(),
|
|
938
1106
|
channel,
|
|
939
1107
|
data: eventData
|
|
940
1108
|
};
|
|
@@ -984,9 +1152,9 @@ var WebSocketHandler = class {
|
|
|
984
1152
|
}
|
|
985
1153
|
}
|
|
986
1154
|
async createReplyMessage(request, replyData) {
|
|
987
|
-
const
|
|
1155
|
+
const crypto2 = await importCrypto();
|
|
988
1156
|
const replyMessage = {
|
|
989
|
-
id:
|
|
1157
|
+
id: crypto2.randomUUID(),
|
|
990
1158
|
channel: request.channel,
|
|
991
1159
|
requestId: request.id,
|
|
992
1160
|
data: replyData
|
|
@@ -1067,12 +1235,14 @@ var WebSocketServer = class extends WebSocketHandler_default {
|
|
|
1067
1235
|
}
|
|
1068
1236
|
webSocketServer;
|
|
1069
1237
|
httpServer;
|
|
1238
|
+
authenticate;
|
|
1070
1239
|
constructor(options) {
|
|
1071
1240
|
super({
|
|
1072
1241
|
socketTimeout: options.socketTimeout,
|
|
1073
1242
|
messageTimeout: options.messageTimeout
|
|
1074
1243
|
});
|
|
1075
1244
|
this.httpServer = options.httpServer;
|
|
1245
|
+
this.authenticate = options.authenticate;
|
|
1076
1246
|
}
|
|
1077
1247
|
get isRunning() {
|
|
1078
1248
|
return this.webSocketServer !== void 0;
|
|
@@ -1085,9 +1255,17 @@ var WebSocketServer = class extends WebSocketHandler_default {
|
|
|
1085
1255
|
webSocketServer.on("error", (error) => {
|
|
1086
1256
|
console.error(error);
|
|
1087
1257
|
});
|
|
1088
|
-
webSocketServer.on("connection", async (socket) => {
|
|
1258
|
+
webSocketServer.on("connection", async (socket, request) => {
|
|
1259
|
+
if (this.authenticate) {
|
|
1260
|
+
const result = await this.authenticate(socket, request);
|
|
1261
|
+
if (!result.isValid) {
|
|
1262
|
+
socket.close(1008, result.message);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1089
1266
|
try {
|
|
1090
1267
|
await super.registerSocket(socket);
|
|
1268
|
+
socket.send("socket:auth:valid");
|
|
1091
1269
|
} catch (error) {
|
|
1092
1270
|
webSocketServer.emit("error", error);
|
|
1093
1271
|
}
|
|
@@ -1108,8 +1286,242 @@ var WebSocketServer = class extends WebSocketHandler_default {
|
|
|
1108
1286
|
};
|
|
1109
1287
|
var WebSocketServer_default = WebSocketServer;
|
|
1110
1288
|
|
|
1289
|
+
// src/server/errors/InvalidInterceptorTokenError.ts
|
|
1290
|
+
var InvalidInterceptorTokenError = class extends Error {
|
|
1291
|
+
static {
|
|
1292
|
+
chunkWCQVDF3K_js.__name(this, "InvalidInterceptorTokenError");
|
|
1293
|
+
}
|
|
1294
|
+
constructor(tokenId) {
|
|
1295
|
+
super(`Invalid interceptor token: ${tokenId}`);
|
|
1296
|
+
this.name = "InvalidInterceptorTokenError";
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
var InvalidInterceptorTokenError_default = InvalidInterceptorTokenError;
|
|
1300
|
+
|
|
1301
|
+
// src/server/errors/InvalidInterceptorTokenFileError.ts
|
|
1302
|
+
var InvalidInterceptorTokenFileError = class extends Error {
|
|
1303
|
+
static {
|
|
1304
|
+
chunkWCQVDF3K_js.__name(this, "InvalidInterceptorTokenFileError");
|
|
1305
|
+
}
|
|
1306
|
+
constructor(tokenFilePath, validationErrorMessage) {
|
|
1307
|
+
super(`Invalid interceptor token file ${tokenFilePath}: ${validationErrorMessage}`);
|
|
1308
|
+
this.name = "InvalidInterceptorTokenFileError";
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
var InvalidInterceptorTokenFileError_default = InvalidInterceptorTokenFileError;
|
|
1312
|
+
|
|
1313
|
+
// src/server/errors/InvalidInterceptorTokenValueError.ts
|
|
1314
|
+
var InvalidInterceptorTokenValueError = class extends Error {
|
|
1315
|
+
static {
|
|
1316
|
+
chunkWCQVDF3K_js.__name(this, "InvalidInterceptorTokenValueError");
|
|
1317
|
+
}
|
|
1318
|
+
constructor(tokenValue) {
|
|
1319
|
+
super(`Invalid interceptor token value: ${tokenValue}`);
|
|
1320
|
+
this.name = "InvalidInterceptorTokenValueError";
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var InvalidInterceptorTokenValueError_default = InvalidInterceptorTokenValueError;
|
|
1324
|
+
|
|
1325
|
+
// src/server/utils/auth.ts
|
|
1326
|
+
var DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY = path__default.default.join(
|
|
1327
|
+
".zimic",
|
|
1328
|
+
"interceptor",
|
|
1329
|
+
"server",
|
|
1330
|
+
`tokens${""}`
|
|
1331
|
+
);
|
|
1332
|
+
var INTERCEPTOR_TOKEN_ID_HEX_LENGTH = 32;
|
|
1333
|
+
var INTERCEPTOR_TOKEN_SECRET_HEX_LENGTH = 64;
|
|
1334
|
+
var INTERCEPTOR_TOKEN_VALUE_HEX_LENGTH = INTERCEPTOR_TOKEN_ID_HEX_LENGTH + INTERCEPTOR_TOKEN_SECRET_HEX_LENGTH;
|
|
1335
|
+
var INTERCEPTOR_TOKEN_VALUE_BASE64URL_LENGTH = convertHexLengthToBase64urlLength(
|
|
1336
|
+
INTERCEPTOR_TOKEN_VALUE_HEX_LENGTH
|
|
1337
|
+
);
|
|
1338
|
+
var INTERCEPTOR_TOKEN_SALT_HEX_LENGTH = 64;
|
|
1339
|
+
var INTERCEPTOR_TOKEN_HASH_ITERATIONS = Number("1000000");
|
|
1340
|
+
var INTERCEPTOR_TOKEN_HASH_HEX_LENGTH = 128;
|
|
1341
|
+
var INTERCEPTOR_TOKEN_HASH_ALGORITHM = "sha512";
|
|
1342
|
+
var pbkdf2 = util__default.default.promisify(crypto__default.default.pbkdf2);
|
|
1343
|
+
async function hashInterceptorToken(plainToken, salt) {
|
|
1344
|
+
const hashBuffer = await pbkdf2(
|
|
1345
|
+
plainToken,
|
|
1346
|
+
salt,
|
|
1347
|
+
INTERCEPTOR_TOKEN_HASH_ITERATIONS,
|
|
1348
|
+
convertHexLengthToByteLength(INTERCEPTOR_TOKEN_HASH_HEX_LENGTH),
|
|
1349
|
+
INTERCEPTOR_TOKEN_HASH_ALGORITHM
|
|
1350
|
+
);
|
|
1351
|
+
const hash = hashBuffer.toString("hex");
|
|
1352
|
+
return hash;
|
|
1353
|
+
}
|
|
1354
|
+
chunkWCQVDF3K_js.__name(hashInterceptorToken, "hashInterceptorToken");
|
|
1355
|
+
function createInterceptorTokenId() {
|
|
1356
|
+
return crypto__default.default.randomUUID().replace(/[^a-z0-9]/g, "");
|
|
1357
|
+
}
|
|
1358
|
+
chunkWCQVDF3K_js.__name(createInterceptorTokenId, "createInterceptorTokenId");
|
|
1359
|
+
function isValidInterceptorTokenId(tokenId) {
|
|
1360
|
+
return tokenId.length === INTERCEPTOR_TOKEN_ID_HEX_LENGTH && HEX_REGEX.test(tokenId);
|
|
1361
|
+
}
|
|
1362
|
+
chunkWCQVDF3K_js.__name(isValidInterceptorTokenId, "isValidInterceptorTokenId");
|
|
1363
|
+
function isValidInterceptorTokenValue(tokenValue) {
|
|
1364
|
+
return tokenValue.length === INTERCEPTOR_TOKEN_VALUE_BASE64URL_LENGTH && BASE64URL_REGEX.test(tokenValue);
|
|
1365
|
+
}
|
|
1366
|
+
chunkWCQVDF3K_js.__name(isValidInterceptorTokenValue, "isValidInterceptorTokenValue");
|
|
1367
|
+
async function createInterceptorTokensDirectory(tokensDirectory) {
|
|
1368
|
+
try {
|
|
1369
|
+
const parentTokensDirectory = path__default.default.dirname(tokensDirectory);
|
|
1370
|
+
await fs__default.default.promises.mkdir(parentTokensDirectory, { recursive: true });
|
|
1371
|
+
await fs__default.default.promises.mkdir(tokensDirectory, { mode: 448, recursive: true });
|
|
1372
|
+
await fs__default.default.promises.appendFile(path__default.default.join(tokensDirectory, ".gitignore"), `*${os__default.default.EOL}`, { encoding: "utf-8" });
|
|
1373
|
+
} catch (error) {
|
|
1374
|
+
logger.error(
|
|
1375
|
+
`${color3__default.default.red(color3__default.default.bold("\u2716"))} Failed to create the tokens directory: ${color3__default.default.magenta(tokensDirectory)}`
|
|
1376
|
+
);
|
|
1377
|
+
throw error;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
chunkWCQVDF3K_js.__name(createInterceptorTokensDirectory, "createInterceptorTokensDirectory");
|
|
1381
|
+
var interceptorTokenFileContentSchema = zod.z.object({
|
|
1382
|
+
version: zod.z.literal(1),
|
|
1383
|
+
token: zod.z.object({
|
|
1384
|
+
id: zod.z.string().length(INTERCEPTOR_TOKEN_ID_HEX_LENGTH).regex(HEX_REGEX),
|
|
1385
|
+
name: zod.z.string().optional(),
|
|
1386
|
+
secret: zod.z.object({
|
|
1387
|
+
hash: zod.z.string().length(INTERCEPTOR_TOKEN_HASH_HEX_LENGTH).regex(HEX_REGEX),
|
|
1388
|
+
salt: zod.z.string().length(INTERCEPTOR_TOKEN_SALT_HEX_LENGTH).regex(HEX_REGEX)
|
|
1389
|
+
}),
|
|
1390
|
+
createdAt: zod.z.string().datetime().transform((value) => new Date(value))
|
|
1391
|
+
})
|
|
1392
|
+
});
|
|
1393
|
+
async function saveInterceptorTokenToFile(tokensDirectory, token) {
|
|
1394
|
+
const tokeFilePath = path__default.default.join(tokensDirectory, token.id);
|
|
1395
|
+
const persistedToken = {
|
|
1396
|
+
id: token.id,
|
|
1397
|
+
name: token.name,
|
|
1398
|
+
secret: {
|
|
1399
|
+
hash: token.secret.hash,
|
|
1400
|
+
salt: token.secret.salt
|
|
1401
|
+
},
|
|
1402
|
+
createdAt: token.createdAt.toISOString()
|
|
1403
|
+
};
|
|
1404
|
+
const tokenFileContent = interceptorTokenFileContentSchema.parse({
|
|
1405
|
+
version: 1,
|
|
1406
|
+
token: persistedToken
|
|
1407
|
+
});
|
|
1408
|
+
await fs__default.default.promises.writeFile(tokeFilePath, JSON.stringify(tokenFileContent, null, 2), {
|
|
1409
|
+
mode: 384,
|
|
1410
|
+
encoding: "utf-8"
|
|
1411
|
+
});
|
|
1412
|
+
return tokeFilePath;
|
|
1413
|
+
}
|
|
1414
|
+
chunkWCQVDF3K_js.__name(saveInterceptorTokenToFile, "saveInterceptorTokenToFile");
|
|
1415
|
+
async function readInterceptorTokenFromFile(tokenId, options) {
|
|
1416
|
+
if (!isValidInterceptorTokenId(tokenId)) {
|
|
1417
|
+
throw new InvalidInterceptorTokenError_default(tokenId);
|
|
1418
|
+
}
|
|
1419
|
+
const tokenFilePath = path__default.default.join(options.tokensDirectory, tokenId);
|
|
1420
|
+
const tokenFileExists = await pathExists(tokenFilePath);
|
|
1421
|
+
if (!tokenFileExists) {
|
|
1422
|
+
return null;
|
|
1423
|
+
}
|
|
1424
|
+
const tokenFileContentAsString = await fs__default.default.promises.readFile(tokenFilePath, { encoding: "utf-8" });
|
|
1425
|
+
const validation = interceptorTokenFileContentSchema.safeParse(JSON.parse(tokenFileContentAsString));
|
|
1426
|
+
if (!validation.success) {
|
|
1427
|
+
throw new InvalidInterceptorTokenFileError_default(tokenFilePath, validation.error.message);
|
|
1428
|
+
}
|
|
1429
|
+
return validation.data.token;
|
|
1430
|
+
}
|
|
1431
|
+
chunkWCQVDF3K_js.__name(readInterceptorTokenFromFile, "readInterceptorTokenFromFile");
|
|
1432
|
+
async function createInterceptorToken(options) {
|
|
1433
|
+
const { name, tokensDirectory } = options;
|
|
1434
|
+
const tokensDirectoryExists = await pathExists(tokensDirectory);
|
|
1435
|
+
if (!tokensDirectoryExists) {
|
|
1436
|
+
await createInterceptorTokensDirectory(tokensDirectory);
|
|
1437
|
+
}
|
|
1438
|
+
const tokenId = createInterceptorTokenId();
|
|
1439
|
+
if (!isValidInterceptorTokenId(tokenId)) {
|
|
1440
|
+
throw new InvalidInterceptorTokenError_default(tokenId);
|
|
1441
|
+
}
|
|
1442
|
+
const tokenSecretSizeInBytes = convertHexLengthToByteLength(INTERCEPTOR_TOKEN_SECRET_HEX_LENGTH);
|
|
1443
|
+
const tokenSecret = crypto__default.default.randomBytes(tokenSecretSizeInBytes).toString("hex");
|
|
1444
|
+
const tokenSecretSaltSizeInBytes = convertHexLengthToByteLength(INTERCEPTOR_TOKEN_SALT_HEX_LENGTH);
|
|
1445
|
+
const tokenSecretSalt = crypto__default.default.randomBytes(tokenSecretSaltSizeInBytes).toString("hex");
|
|
1446
|
+
const tokenSecretHash = await hashInterceptorToken(tokenSecret, tokenSecretSalt);
|
|
1447
|
+
const tokenValue = Buffer.from(`${tokenId}${tokenSecret}`, "hex").toString("base64url");
|
|
1448
|
+
if (!isValidInterceptorTokenValue(tokenValue)) {
|
|
1449
|
+
throw new InvalidInterceptorTokenValueError_default(tokenValue);
|
|
1450
|
+
}
|
|
1451
|
+
const token = {
|
|
1452
|
+
id: tokenId,
|
|
1453
|
+
name,
|
|
1454
|
+
secret: {
|
|
1455
|
+
hash: tokenSecretHash,
|
|
1456
|
+
salt: tokenSecretSalt,
|
|
1457
|
+
value: tokenSecret
|
|
1458
|
+
},
|
|
1459
|
+
value: tokenValue,
|
|
1460
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
1461
|
+
};
|
|
1462
|
+
await saveInterceptorTokenToFile(tokensDirectory, token);
|
|
1463
|
+
return token;
|
|
1464
|
+
}
|
|
1465
|
+
chunkWCQVDF3K_js.__name(createInterceptorToken, "createInterceptorToken");
|
|
1466
|
+
async function listInterceptorTokens(options) {
|
|
1467
|
+
const tokensDirectoryExists = await pathExists(options.tokensDirectory);
|
|
1468
|
+
if (!tokensDirectoryExists) {
|
|
1469
|
+
return [];
|
|
1470
|
+
}
|
|
1471
|
+
const files = await fs__default.default.promises.readdir(options.tokensDirectory);
|
|
1472
|
+
const tokenReadPromises = files.map(async (file) => {
|
|
1473
|
+
if (!isValidInterceptorTokenId(file)) {
|
|
1474
|
+
return null;
|
|
1475
|
+
}
|
|
1476
|
+
const tokenId = file;
|
|
1477
|
+
const token = await readInterceptorTokenFromFile(tokenId, options);
|
|
1478
|
+
return token;
|
|
1479
|
+
});
|
|
1480
|
+
const tokenCandidates = await Promise.allSettled(tokenReadPromises);
|
|
1481
|
+
const tokens = [];
|
|
1482
|
+
for (const tokenCandidate of tokenCandidates) {
|
|
1483
|
+
if (tokenCandidate.status === "rejected") {
|
|
1484
|
+
console.error(tokenCandidate.reason);
|
|
1485
|
+
} else if (tokenCandidate.value !== null) {
|
|
1486
|
+
tokens.push(tokenCandidate.value);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
tokens.sort((token, otherToken) => token.createdAt.getTime() - otherToken.createdAt.getTime());
|
|
1490
|
+
return tokens;
|
|
1491
|
+
}
|
|
1492
|
+
chunkWCQVDF3K_js.__name(listInterceptorTokens, "listInterceptorTokens");
|
|
1493
|
+
async function validateInterceptorToken(tokenValue, options) {
|
|
1494
|
+
if (!isValidInterceptorTokenValue(tokenValue)) {
|
|
1495
|
+
throw new InvalidInterceptorTokenValueError_default(tokenValue);
|
|
1496
|
+
}
|
|
1497
|
+
const decodedTokenValue = Buffer.from(tokenValue, "base64url").toString("hex");
|
|
1498
|
+
const tokenId = decodedTokenValue.slice(0, INTERCEPTOR_TOKEN_ID_HEX_LENGTH);
|
|
1499
|
+
const tokenSecret = decodedTokenValue.slice(
|
|
1500
|
+
INTERCEPTOR_TOKEN_ID_HEX_LENGTH,
|
|
1501
|
+
INTERCEPTOR_TOKEN_ID_HEX_LENGTH + INTERCEPTOR_TOKEN_VALUE_HEX_LENGTH
|
|
1502
|
+
);
|
|
1503
|
+
const tokenFromFile = await readInterceptorTokenFromFile(tokenId, options);
|
|
1504
|
+
if (!tokenFromFile) {
|
|
1505
|
+
throw new InvalidInterceptorTokenValueError_default(tokenValue);
|
|
1506
|
+
}
|
|
1507
|
+
const tokenSecretHash = await hashInterceptorToken(tokenSecret, tokenFromFile.secret.salt);
|
|
1508
|
+
if (tokenSecretHash !== tokenFromFile.secret.hash) {
|
|
1509
|
+
throw new InvalidInterceptorTokenValueError_default(tokenValue);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
chunkWCQVDF3K_js.__name(validateInterceptorToken, "validateInterceptorToken");
|
|
1513
|
+
async function removeInterceptorToken(tokenId, options) {
|
|
1514
|
+
if (!isValidInterceptorTokenId(tokenId)) {
|
|
1515
|
+
throw new InvalidInterceptorTokenError_default(tokenId);
|
|
1516
|
+
}
|
|
1517
|
+
const tokenFilePath = path__default.default.join(options.tokensDirectory, tokenId);
|
|
1518
|
+
await fs__default.default.promises.rm(tokenFilePath, { force: true });
|
|
1519
|
+
}
|
|
1520
|
+
chunkWCQVDF3K_js.__name(removeInterceptorToken, "removeInterceptorToken");
|
|
1521
|
+
|
|
1111
1522
|
// src/server/utils/fetch.ts
|
|
1112
1523
|
async function getFetchAPI() {
|
|
1524
|
+
const File2 = await importFile();
|
|
1113
1525
|
return {
|
|
1114
1526
|
fetch,
|
|
1115
1527
|
Request,
|
|
@@ -1124,7 +1536,7 @@ async function getFetchAPI() {
|
|
|
1124
1536
|
TextDecoderStream,
|
|
1125
1537
|
TextEncoderStream,
|
|
1126
1538
|
Blob,
|
|
1127
|
-
File:
|
|
1539
|
+
File: File2,
|
|
1128
1540
|
crypto: globalThis.crypto,
|
|
1129
1541
|
btoa,
|
|
1130
1542
|
TextEncoder,
|
|
@@ -1146,6 +1558,7 @@ var InterceptorServer = class {
|
|
|
1146
1558
|
_hostname;
|
|
1147
1559
|
_port;
|
|
1148
1560
|
logUnhandledRequests;
|
|
1561
|
+
tokensDirectory;
|
|
1149
1562
|
httpHandlerGroups = {
|
|
1150
1563
|
GET: [],
|
|
1151
1564
|
POST: [],
|
|
@@ -1160,6 +1573,7 @@ var InterceptorServer = class {
|
|
|
1160
1573
|
this._hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
1161
1574
|
this._port = options.port;
|
|
1162
1575
|
this.logUnhandledRequests = options.logUnhandledRequests ?? DEFAULT_LOG_UNHANDLED_REQUESTS;
|
|
1576
|
+
this.tokensDirectory = options.tokensDirectory;
|
|
1163
1577
|
}
|
|
1164
1578
|
get hostname() {
|
|
1165
1579
|
return this._hostname;
|
|
@@ -1204,10 +1618,39 @@ var InterceptorServer = class {
|
|
|
1204
1618
|
});
|
|
1205
1619
|
await this.startHttpServer();
|
|
1206
1620
|
this.webSocketServer = new WebSocketServer_default({
|
|
1207
|
-
httpServer: this.httpServer
|
|
1621
|
+
httpServer: this.httpServer,
|
|
1622
|
+
authenticate: this.authenticateWebSocketConnection
|
|
1208
1623
|
});
|
|
1209
1624
|
this.startWebSocketServer();
|
|
1210
1625
|
}
|
|
1626
|
+
authenticateWebSocketConnection = /* @__PURE__ */ chunkWCQVDF3K_js.__name(async (_socket, request) => {
|
|
1627
|
+
if (!this.tokensDirectory) {
|
|
1628
|
+
return { isValid: true };
|
|
1629
|
+
}
|
|
1630
|
+
const tokenValue = this.getWebSocketRequestTokenValue(request);
|
|
1631
|
+
if (!tokenValue) {
|
|
1632
|
+
return { isValid: false, message: "An interceptor token is required, but none was provided." };
|
|
1633
|
+
}
|
|
1634
|
+
try {
|
|
1635
|
+
await validateInterceptorToken(tokenValue, { tokensDirectory: this.tokensDirectory });
|
|
1636
|
+
return { isValid: true };
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
console.error(error);
|
|
1639
|
+
return { isValid: false, message: "The interceptor token is not valid." };
|
|
1640
|
+
}
|
|
1641
|
+
}, "authenticateWebSocketConnection");
|
|
1642
|
+
getWebSocketRequestTokenValue(request) {
|
|
1643
|
+
const protocols = request.headers["sec-websocket-protocol"] ?? "";
|
|
1644
|
+
const parametersAsString = decodeURIComponent(protocols).split(", ");
|
|
1645
|
+
for (const parameterAsString of parametersAsString) {
|
|
1646
|
+
const tokenValueMatch = /^token=(?<tokenValue>.+?)$/.exec(parameterAsString);
|
|
1647
|
+
const tokenValue = tokenValueMatch?.groups?.tokenValue;
|
|
1648
|
+
if (tokenValue) {
|
|
1649
|
+
return tokenValue;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
return void 0;
|
|
1653
|
+
}
|
|
1211
1654
|
async startHttpServer() {
|
|
1212
1655
|
await startHttpServer(this.httpServerOrThrow, {
|
|
1213
1656
|
hostname: this.hostname,
|
|
@@ -1218,8 +1661,8 @@ var InterceptorServer = class {
|
|
|
1218
1661
|
}
|
|
1219
1662
|
startWebSocketServer() {
|
|
1220
1663
|
this.webSocketServerOrThrow.start();
|
|
1221
|
-
this.webSocketServerOrThrow.onEvent("interceptors/workers/
|
|
1222
|
-
this.webSocketServerOrThrow.onEvent("interceptors/workers/
|
|
1664
|
+
this.webSocketServerOrThrow.onEvent("interceptors/workers/commit", this.commitWorker);
|
|
1665
|
+
this.webSocketServerOrThrow.onEvent("interceptors/workers/reset", this.resetWorker);
|
|
1223
1666
|
}
|
|
1224
1667
|
commitWorker = /* @__PURE__ */ chunkWCQVDF3K_js.__name((message, socket) => {
|
|
1225
1668
|
const commit = message.data;
|
|
@@ -1283,8 +1726,8 @@ var InterceptorServer = class {
|
|
|
1283
1726
|
this.httpServer = void 0;
|
|
1284
1727
|
}
|
|
1285
1728
|
async stopWebSocketServer() {
|
|
1286
|
-
this.webSocketServerOrThrow.offEvent("interceptors/workers/
|
|
1287
|
-
this.webSocketServerOrThrow.offEvent("interceptors/workers/
|
|
1729
|
+
this.webSocketServerOrThrow.offEvent("interceptors/workers/commit", this.commitWorker);
|
|
1730
|
+
this.webSocketServerOrThrow.offEvent("interceptors/workers/reset", this.resetWorker);
|
|
1288
1731
|
await this.webSocketServerOrThrow.stop();
|
|
1289
1732
|
this.webSocketServer = void 0;
|
|
1290
1733
|
}
|
|
@@ -1396,6 +1839,10 @@ chunkWCQVDF3K_js.__name(createInterceptorServer, "createInterceptorServer");
|
|
|
1396
1839
|
* This is expected not to happen since the servers are not stopped unless they are running. */
|
|
1397
1840
|
/* istanbul ignore if -- @preserve
|
|
1398
1841
|
* The address is expected to be an object because the server does not listen on a pipe or Unix domain socket. */
|
|
1842
|
+
/* istanbul ignore else -- @preserve
|
|
1843
|
+
* An unauthorized close event is the only one we expect to happen here. */
|
|
1844
|
+
/* istanbul ignore else -- @preserve
|
|
1845
|
+
* We currently only support the 'socket:auth:valid' message and it is the only possible control message here. */
|
|
1399
1846
|
/* istanbul ignore if -- @preserve
|
|
1400
1847
|
* This is not expected since the server is not stopped unless it is running. */
|
|
1401
1848
|
/* istanbul ignore next -- @preserve
|
|
@@ -1407,6 +1854,12 @@ chunkWCQVDF3K_js.__name(createInterceptorServer, "createInterceptorServer");
|
|
|
1407
1854
|
/* istanbul ignore next -- @preserve
|
|
1408
1855
|
* Reply listeners are always present when notified in normal conditions. If they were not present, the request
|
|
1409
1856
|
* would reach a timeout and not be responded. The empty set serves as a fallback. */
|
|
1857
|
+
/* istanbul ignore if -- @preserve
|
|
1858
|
+
* This should never happen, but let's check that the token identifier is valid after generated. */
|
|
1859
|
+
/* istanbul ignore if -- @preserve
|
|
1860
|
+
* This should never happen, but let's check that the token value is valid after generated. */
|
|
1861
|
+
/* istanbul ignore if -- @preserve
|
|
1862
|
+
* At this point, we should have a valid tokenId. This is just a sanity check. */
|
|
1410
1863
|
/* istanbul ignore if -- @preserve
|
|
1411
1864
|
* The HTTP server is initialized before using this method in normal conditions. */
|
|
1412
1865
|
/* istanbul ignore if -- @preserve
|
|
@@ -1418,11 +1871,16 @@ chunkWCQVDF3K_js.__name(createInterceptorServer, "createInterceptorServer");
|
|
|
1418
1871
|
* Since simulating this scenario is difficult, we are ignoring this branch fow now. */
|
|
1419
1872
|
|
|
1420
1873
|
exports.DEFAULT_ACCESS_CONTROL_HEADERS = DEFAULT_ACCESS_CONTROL_HEADERS;
|
|
1874
|
+
exports.DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY = DEFAULT_INTERCEPTOR_TOKENS_DIRECTORY;
|
|
1421
1875
|
exports.DEFAULT_PREFLIGHT_STATUS_CODE = DEFAULT_PREFLIGHT_STATUS_CODE;
|
|
1422
1876
|
exports.NotRunningInterceptorServerError_default = NotRunningInterceptorServerError_default;
|
|
1423
1877
|
exports.RunningInterceptorServerError_default = RunningInterceptorServerError_default;
|
|
1424
1878
|
exports.createCachedDynamicImport_default = createCachedDynamicImport_default;
|
|
1425
1879
|
exports.createInterceptorServer = createInterceptorServer;
|
|
1426
|
-
exports.
|
|
1427
|
-
|
|
1428
|
-
|
|
1880
|
+
exports.createInterceptorToken = createInterceptorToken;
|
|
1881
|
+
exports.listInterceptorTokens = listInterceptorTokens;
|
|
1882
|
+
exports.logger = logger;
|
|
1883
|
+
exports.readInterceptorTokenFromFile = readInterceptorTokenFromFile;
|
|
1884
|
+
exports.removeInterceptorToken = removeInterceptorToken;
|
|
1885
|
+
//# sourceMappingURL=chunk-PURXNE6R.js.map
|
|
1886
|
+
//# sourceMappingURL=chunk-PURXNE6R.js.map
|