@replayio-app-building/netlify-recorder 0.21.0 → 0.22.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/index.d.ts +0 -18
- package/dist/index.js +13 -45
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -205,24 +205,6 @@ interface CreateRecordingRequestHandlerOptions extends FinishRequestOptions {
|
|
|
205
205
|
*/
|
|
206
206
|
declare function createRecordingRequestHandler(handler: (event: NetlifyEvent | NetlifyV2Request, context?: unknown) => Promise<HandlerResponse>, options: CreateRecordingRequestHandlerOptions): (event: NetlifyEvent | NetlifyV2Request, context?: unknown) => Promise<HandlerResponse>;
|
|
207
207
|
|
|
208
|
-
/**
|
|
209
|
-
* Redacts sensitive environment variable values from blob data.
|
|
210
|
-
*
|
|
211
|
-
* This function performs two passes:
|
|
212
|
-
*
|
|
213
|
-
* Pass 1 — Redact env reads:
|
|
214
|
-
* For each captured EnvRead whose value should be redacted,
|
|
215
|
-
* replace the value with a "*"-repeated string of the same length.
|
|
216
|
-
*
|
|
217
|
-
* Pass 2 — Scrub the rest of the blob:
|
|
218
|
-
* Any redacted value that appears elsewhere in the blob data
|
|
219
|
-
* (network call headers, bodies, request info headers/body) is
|
|
220
|
-
* also replaced with the same mask. This prevents secrets from
|
|
221
|
-
* leaking through, e.g., an Authorization header that embeds
|
|
222
|
-
* an API key captured via process.env.
|
|
223
|
-
*
|
|
224
|
-
* The function returns a new BlobData object; the input is not mutated.
|
|
225
|
-
*/
|
|
226
208
|
declare function redactBlobData(blobData: BlobData): BlobData;
|
|
227
209
|
|
|
228
210
|
interface RecordingResult {
|
package/dist/index.js
CHANGED
|
@@ -417,11 +417,8 @@ function shouldRedact(key, value) {
|
|
|
417
417
|
if (value === void 0 || value.length <= 8) return false;
|
|
418
418
|
return true;
|
|
419
419
|
}
|
|
420
|
-
function replaceAll(text, searchValue,
|
|
421
|
-
return text.split(searchValue).join(
|
|
422
|
-
}
|
|
423
|
-
function buildMask(value) {
|
|
424
|
-
return "*".repeat(value.length);
|
|
420
|
+
function replaceAll(text, searchValue, replacement) {
|
|
421
|
+
return text.split(searchValue).join(replacement);
|
|
425
422
|
}
|
|
426
423
|
function buildPlaceholder(key) {
|
|
427
424
|
if (key === "DATABASE_URL" || key.endsWith("_DATABASE_URL")) {
|
|
@@ -430,20 +427,18 @@ function buildPlaceholder(key) {
|
|
|
430
427
|
return `placeholder_${key.toLowerCase()}`;
|
|
431
428
|
}
|
|
432
429
|
function redactBlobData(blobData) {
|
|
433
|
-
const
|
|
434
|
-
const placeholders = /* @__PURE__ */ new Map();
|
|
430
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
435
431
|
const redactedEnvReads = blobData.capturedData.envReads.map(
|
|
436
432
|
(read) => {
|
|
437
433
|
if (shouldRedact(read.key, read.value) && read.value !== void 0) {
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
return { ...read, value: mask };
|
|
434
|
+
const placeholder = buildPlaceholder(read.key);
|
|
435
|
+
replacements.set(read.value, placeholder);
|
|
436
|
+
return { ...read, value: placeholder };
|
|
442
437
|
}
|
|
443
438
|
return { ...read };
|
|
444
439
|
}
|
|
445
440
|
);
|
|
446
|
-
if (
|
|
441
|
+
if (replacements.size === 0) {
|
|
447
442
|
return {
|
|
448
443
|
...blobData,
|
|
449
444
|
capturedData: {
|
|
@@ -452,14 +447,14 @@ function redactBlobData(blobData) {
|
|
|
452
447
|
}
|
|
453
448
|
};
|
|
454
449
|
}
|
|
455
|
-
const
|
|
450
|
+
const sorted = [...replacements.entries()].sort(
|
|
456
451
|
(a, b) => b[0].length - a[0].length
|
|
457
452
|
);
|
|
458
453
|
function scrub(text) {
|
|
459
454
|
if (text === void 0) return void 0;
|
|
460
455
|
let result = text;
|
|
461
|
-
for (const [original,
|
|
462
|
-
result = replaceAll(result, original,
|
|
456
|
+
for (const [original, placeholder] of sorted) {
|
|
457
|
+
result = replaceAll(result, original, placeholder);
|
|
463
458
|
}
|
|
464
459
|
return result;
|
|
465
460
|
}
|
|
@@ -470,29 +465,11 @@ function redactBlobData(blobData) {
|
|
|
470
465
|
}
|
|
471
466
|
return out;
|
|
472
467
|
}
|
|
473
|
-
const sortedPlaceholders = [...placeholders.entries()].sort(
|
|
474
|
-
(a, b) => b[0].length - a[0].length
|
|
475
|
-
);
|
|
476
|
-
function scrubForRequest(text) {
|
|
477
|
-
if (text === void 0) return void 0;
|
|
478
|
-
let result = text;
|
|
479
|
-
for (const [original, placeholder] of sortedPlaceholders) {
|
|
480
|
-
result = replaceAll(result, original, placeholder);
|
|
481
|
-
}
|
|
482
|
-
return result;
|
|
483
|
-
}
|
|
484
|
-
function scrubHeadersForRequest(headers) {
|
|
485
|
-
const out = {};
|
|
486
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
487
|
-
out[k] = scrubForRequest(v) ?? v;
|
|
488
|
-
}
|
|
489
|
-
return out;
|
|
490
|
-
}
|
|
491
468
|
const redactedRequestInfo = {
|
|
492
469
|
...blobData.requestInfo,
|
|
493
|
-
url:
|
|
494
|
-
headers:
|
|
495
|
-
body:
|
|
470
|
+
url: scrub(blobData.requestInfo.url) ?? blobData.requestInfo.url,
|
|
471
|
+
headers: scrubHeaders(blobData.requestInfo.headers),
|
|
472
|
+
body: scrub(blobData.requestInfo.body)
|
|
496
473
|
};
|
|
497
474
|
const redactedNetworkCalls = blobData.capturedData.networkCalls.map(
|
|
498
475
|
(call) => ({
|
|
@@ -643,15 +620,6 @@ async function createRequestRecording(blobUrlOrData, handlerPath, requestInfo) {
|
|
|
643
620
|
} else {
|
|
644
621
|
blobData = blobUrlOrData;
|
|
645
622
|
}
|
|
646
|
-
for (const read of blobData.capturedData.envReads) {
|
|
647
|
-
if (read.value && read.value.length > 8 && /^\*+$/.test(read.value)) {
|
|
648
|
-
if (read.key === "DATABASE_URL" || read.key.endsWith("_DATABASE_URL")) {
|
|
649
|
-
read.value = "postgresql://replay:replay@localhost:5432/replay";
|
|
650
|
-
} else {
|
|
651
|
-
read.value = `placeholder_${read.key.toLowerCase()}`;
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
623
|
const networkHandle = installNetworkInterceptor(
|
|
656
624
|
"replay",
|
|
657
625
|
blobData.capturedData.networkCalls
|