hppx 0.1.10 → 0.2.2
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/README.md +492 -351
- package/dist/index.cjs +197 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.mjs +196 -84
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -20
- package/src/index.d.cts +0 -70
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
DANGEROUS_KEYS: () => DANGEROUS_KEYS,
|
|
24
24
|
DEFAULT_SOURCES: () => DEFAULT_SOURCES,
|
|
25
25
|
DEFAULT_STRATEGY: () => DEFAULT_STRATEGY,
|
|
26
|
+
__resetPathSegmentCache: () => __resetPathSegmentCache,
|
|
26
27
|
default: () => hppx,
|
|
27
28
|
sanitize: () => sanitize
|
|
28
29
|
});
|
|
@@ -30,6 +31,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
30
31
|
var DEFAULT_SOURCES = ["query", "body", "params"];
|
|
31
32
|
var DEFAULT_STRATEGY = "keepLast";
|
|
32
33
|
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
34
|
+
var FORBIDDEN_KEY_CHARS = /[\u0000-\u001F\u007F-\u009F\u200E\u200F\u202A-\u202E\u2066-\u2069\uFEFF]/;
|
|
33
35
|
function isPlainObject(value) {
|
|
34
36
|
if (value === null || typeof value !== "object") return false;
|
|
35
37
|
const proto = Object.getPrototypeOf(value);
|
|
@@ -38,23 +40,28 @@ function isPlainObject(value) {
|
|
|
38
40
|
function sanitizeKey(key, maxKeyLength) {
|
|
39
41
|
if (typeof key !== "string") return null;
|
|
40
42
|
if (DANGEROUS_KEYS.has(key)) return null;
|
|
41
|
-
if (
|
|
43
|
+
if (FORBIDDEN_KEY_CHARS.test(key)) return null;
|
|
42
44
|
const maxLen = maxKeyLength ?? 200;
|
|
43
45
|
if (key.length > maxLen) return null;
|
|
44
46
|
if (key.length > 1 && /^[.\[\]]+$/.test(key)) return null;
|
|
45
47
|
return key;
|
|
46
48
|
}
|
|
49
|
+
var PATH_SEGMENT_CACHE_LIMIT = 500;
|
|
47
50
|
var pathSegmentCache = /* @__PURE__ */ new Map();
|
|
48
51
|
function parsePathSegments(key) {
|
|
49
52
|
const cached = pathSegmentCache.get(key);
|
|
50
53
|
if (cached) return cached;
|
|
51
54
|
const dotted = key.replace(/\]/g, "").replace(/\[/g, ".");
|
|
52
55
|
const result = dotted.split(".").filter((s) => s.length > 0);
|
|
53
|
-
if (pathSegmentCache.size
|
|
54
|
-
pathSegmentCache.
|
|
56
|
+
if (pathSegmentCache.size >= PATH_SEGMENT_CACHE_LIMIT) {
|
|
57
|
+
pathSegmentCache.clear();
|
|
55
58
|
}
|
|
59
|
+
pathSegmentCache.set(key, result);
|
|
56
60
|
return result;
|
|
57
61
|
}
|
|
62
|
+
function __resetPathSegmentCache() {
|
|
63
|
+
pathSegmentCache.clear();
|
|
64
|
+
}
|
|
58
65
|
function expandObjectPaths(obj, maxKeyLength, maxDepth = 20, currentDepth = 0, seen) {
|
|
59
66
|
if (currentDepth > maxDepth) {
|
|
60
67
|
throw new Error(`Maximum object depth (${maxDepth}) exceeded`);
|
|
@@ -62,35 +69,36 @@ function expandObjectPaths(obj, maxKeyLength, maxDepth = 20, currentDepth = 0, s
|
|
|
62
69
|
const seenSet = seen ?? /* @__PURE__ */ new WeakSet();
|
|
63
70
|
if (seenSet.has(obj)) return {};
|
|
64
71
|
seenSet.add(obj);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
value
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
try {
|
|
73
|
+
const result = {};
|
|
74
|
+
for (const rawKey of Object.keys(obj)) {
|
|
75
|
+
const safeKey = sanitizeKey(rawKey, maxKeyLength);
|
|
76
|
+
if (!safeKey) continue;
|
|
77
|
+
const value = obj[rawKey];
|
|
78
|
+
const expandedValue = isPlainObject(value) ? expandObjectPaths(
|
|
79
|
+
value,
|
|
80
|
+
maxKeyLength,
|
|
81
|
+
maxDepth,
|
|
82
|
+
currentDepth + 1,
|
|
83
|
+
seenSet
|
|
84
|
+
) : value;
|
|
85
|
+
if (safeKey.includes(".") || safeKey.includes("[")) {
|
|
86
|
+
const segments = parsePathSegments(safeKey);
|
|
87
|
+
if (segments.length > 0) {
|
|
88
|
+
setIn(result, segments, expandedValue);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
82
91
|
}
|
|
92
|
+
result[safeKey] = expandedValue;
|
|
83
93
|
}
|
|
84
|
-
result
|
|
94
|
+
return result;
|
|
95
|
+
} finally {
|
|
96
|
+
seenSet.delete(obj);
|
|
85
97
|
}
|
|
86
|
-
return result;
|
|
87
98
|
}
|
|
88
|
-
function setReqPropertySafe(target, key, value) {
|
|
99
|
+
function setReqPropertySafe(target, key, value, onFailure) {
|
|
89
100
|
try {
|
|
90
101
|
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
91
|
-
if (desc && desc.configurable === false && desc.writable === false) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
102
|
if (!desc || desc.configurable !== false) {
|
|
95
103
|
Object.defineProperty(target, key, {
|
|
96
104
|
value,
|
|
@@ -98,13 +106,35 @@ function setReqPropertySafe(target, key, value) {
|
|
|
98
106
|
configurable: true,
|
|
99
107
|
enumerable: true
|
|
100
108
|
});
|
|
101
|
-
return;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (desc.writable) {
|
|
112
|
+
target[key] = value;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
target[key] = value;
|
|
117
|
+
if (target[key] === value) return true;
|
|
118
|
+
} catch (_assignErr) {
|
|
119
|
+
}
|
|
120
|
+
if (onFailure) {
|
|
121
|
+
onFailure(
|
|
122
|
+
`[hppx] Could not write sanitized value to req.${key}: property is non-configurable and non-writable. The original (potentially polluted) value remains on req.${key}.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
} catch (_definePropErr) {
|
|
127
|
+
try {
|
|
128
|
+
target[key] = value;
|
|
129
|
+
if (target[key] === value) return true;
|
|
130
|
+
} catch (_assignErr) {
|
|
131
|
+
}
|
|
132
|
+
{
|
|
133
|
+
if (onFailure) {
|
|
134
|
+
onFailure(`[hppx] Could not write sanitized value to req.${key}: defineProperty failed.`);
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
102
137
|
}
|
|
103
|
-
} catch (_) {
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
target[key] = value;
|
|
107
|
-
} catch (_) {
|
|
108
138
|
}
|
|
109
139
|
}
|
|
110
140
|
function safeDeepClone(input, maxKeyLength, maxArrayLength, maxDepth = 20, currentDepth = 0, seen) {
|
|
@@ -115,11 +145,15 @@ function safeDeepClone(input, maxKeyLength, maxArrayLength, maxDepth = 20, curre
|
|
|
115
145
|
const seenSet = seen ?? /* @__PURE__ */ new WeakSet();
|
|
116
146
|
if (seenSet.has(input)) return [];
|
|
117
147
|
seenSet.add(input);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
148
|
+
try {
|
|
149
|
+
const limit = maxArrayLength ?? 1e3;
|
|
150
|
+
const limited = input.slice(0, limit);
|
|
151
|
+
return limited.map(
|
|
152
|
+
(v) => safeDeepClone(v, maxKeyLength, maxArrayLength, maxDepth, currentDepth + 1, seenSet)
|
|
153
|
+
);
|
|
154
|
+
} finally {
|
|
155
|
+
seenSet.delete(input);
|
|
156
|
+
}
|
|
123
157
|
}
|
|
124
158
|
if (isPlainObject(input)) {
|
|
125
159
|
if (currentDepth > maxDepth) {
|
|
@@ -128,19 +162,23 @@ function safeDeepClone(input, maxKeyLength, maxArrayLength, maxDepth = 20, curre
|
|
|
128
162
|
const seenSet = seen ?? /* @__PURE__ */ new WeakSet();
|
|
129
163
|
if (seenSet.has(input)) return {};
|
|
130
164
|
seenSet.add(input);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
165
|
+
try {
|
|
166
|
+
const out = {};
|
|
167
|
+
for (const k of Object.keys(input)) {
|
|
168
|
+
if (!sanitizeKey(k, maxKeyLength)) continue;
|
|
169
|
+
out[k] = safeDeepClone(
|
|
170
|
+
input[k],
|
|
171
|
+
maxKeyLength,
|
|
172
|
+
maxArrayLength,
|
|
173
|
+
maxDepth,
|
|
174
|
+
currentDepth + 1,
|
|
175
|
+
seenSet
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
} finally {
|
|
180
|
+
seenSet.delete(input);
|
|
142
181
|
}
|
|
143
|
-
return out;
|
|
144
182
|
}
|
|
145
183
|
return input;
|
|
146
184
|
}
|
|
@@ -156,9 +194,15 @@ function mergeValues(values, strategy) {
|
|
|
156
194
|
else acc.push(v);
|
|
157
195
|
return acc;
|
|
158
196
|
}, []);
|
|
159
|
-
/* istanbul ignore next --
|
|
160
|
-
|
|
161
|
-
|
|
197
|
+
/* istanbul ignore next -- exhaustiveness check unreachable from outside:
|
|
198
|
+
validateSanitizeOptions rejects every non-listed strategy at construction
|
|
199
|
+
time, so the only way to reach this branch is a programmer error (a new
|
|
200
|
+
MergeStrategy union member added without updating this switch). Failing
|
|
201
|
+
loudly here is preferable to a silent fallback. */
|
|
202
|
+
default: {
|
|
203
|
+
const _exhaustive = strategy;
|
|
204
|
+
throw new Error(`Unknown mergeStrategy: ${_exhaustive}`);
|
|
205
|
+
}
|
|
162
206
|
}
|
|
163
207
|
}
|
|
164
208
|
function isUrlEncodedContentType(req) {
|
|
@@ -182,6 +226,7 @@ function normalizeWhitelist(whitelist) {
|
|
|
182
226
|
if (typeof whitelist === "string") return [whitelist];
|
|
183
227
|
return whitelist.filter((w) => typeof w === "string");
|
|
184
228
|
}
|
|
229
|
+
var WHITELIST_PATH_CACHE_LIMIT = 1e3;
|
|
185
230
|
function buildWhitelistHelpers(whitelist) {
|
|
186
231
|
const exact = new Set(whitelist);
|
|
187
232
|
const prefixes = whitelist.filter((w) => w.length > 0);
|
|
@@ -207,9 +252,10 @@ function buildWhitelistHelpers(whitelist) {
|
|
|
207
252
|
}
|
|
208
253
|
}
|
|
209
254
|
}
|
|
210
|
-
if (pathCache.size
|
|
211
|
-
pathCache.
|
|
255
|
+
if (pathCache.size >= WHITELIST_PATH_CACHE_LIMIT) {
|
|
256
|
+
pathCache.clear();
|
|
212
257
|
}
|
|
258
|
+
pathCache.set(full, result);
|
|
213
259
|
return result;
|
|
214
260
|
}
|
|
215
261
|
};
|
|
@@ -257,25 +303,18 @@ function moveWhitelistedFromPolluted(reqPart, polluted, isWhitelisted) {
|
|
|
257
303
|
function detectAndReduce(input, opts) {
|
|
258
304
|
let keyCount = 0;
|
|
259
305
|
const polluted = {};
|
|
260
|
-
const
|
|
261
|
-
|
|
306
|
+
const pollutedKeysSet = /* @__PURE__ */ new Set();
|
|
307
|
+
const cloned = safeDeepClone(input, opts.maxKeyLength, opts.maxArrayLength, opts.maxDepth);
|
|
308
|
+
function processNode(node, path = [], depth = 0, inArray = false) {
|
|
262
309
|
if (node === null) return opts.preserveNull ? null : void 0;
|
|
263
310
|
if (node === void 0) return node;
|
|
264
311
|
if (Array.isArray(node)) {
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return mergeValues(mapped, "combine");
|
|
312
|
+
const mapped = node.map((v) => processNode(v, path, depth, true));
|
|
313
|
+
if (!inArray) {
|
|
314
|
+
setIn(polluted, path, node);
|
|
315
|
+
pollutedKeysSet.add(path.join("."));
|
|
270
316
|
}
|
|
271
|
-
|
|
272
|
-
polluted,
|
|
273
|
-
path,
|
|
274
|
-
safeDeepClone(limitedNode, opts.maxKeyLength, opts.maxArrayLength, opts.maxDepth)
|
|
275
|
-
);
|
|
276
|
-
pollutedKeys.push(path.join("."));
|
|
277
|
-
const reduced = mergeValues(mapped, opts.mergeStrategy);
|
|
278
|
-
return reduced;
|
|
317
|
+
return mergeValues(mapped, opts.mergeStrategy);
|
|
279
318
|
}
|
|
280
319
|
if (isPlainObject(node)) {
|
|
281
320
|
if (depth > opts.maxDepth)
|
|
@@ -290,7 +329,7 @@ function detectAndReduce(input, opts) {
|
|
|
290
329
|
if (!safeKey) continue;
|
|
291
330
|
const child = node[rawKey];
|
|
292
331
|
const childPath = path.concat([safeKey]);
|
|
293
|
-
let value = processNode(child, childPath, depth + 1);
|
|
332
|
+
let value = processNode(child, childPath, depth + 1, false);
|
|
294
333
|
if (typeof value === "string" && opts.trimValues) value = value.trim();
|
|
295
334
|
out[safeKey] = value;
|
|
296
335
|
}
|
|
@@ -298,9 +337,8 @@ function detectAndReduce(input, opts) {
|
|
|
298
337
|
}
|
|
299
338
|
return node;
|
|
300
339
|
}
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
return { cleaned, pollutedTree: polluted, pollutedKeys };
|
|
340
|
+
const cleaned = processNode(cloned, [], 0, false);
|
|
341
|
+
return { cleaned, pollutedTree: polluted, pollutedKeys: Array.from(pollutedKeysSet) };
|
|
304
342
|
}
|
|
305
343
|
function sanitize(input, options = {}) {
|
|
306
344
|
validateSanitizeOptions(options);
|
|
@@ -345,6 +383,24 @@ function validateSanitizeOptions(options) {
|
|
|
345
383
|
if (options.mergeStrategy !== void 0 && !["keepFirst", "keepLast", "combine"].includes(options.mergeStrategy)) {
|
|
346
384
|
throw new TypeError("mergeStrategy must be 'keepFirst', 'keepLast', or 'combine'");
|
|
347
385
|
}
|
|
386
|
+
if (options.trimValues !== void 0 && typeof options.trimValues !== "boolean") {
|
|
387
|
+
throw new TypeError("trimValues must be a boolean");
|
|
388
|
+
}
|
|
389
|
+
if (options.preserveNull !== void 0 && typeof options.preserveNull !== "boolean") {
|
|
390
|
+
throw new TypeError("preserveNull must be a boolean");
|
|
391
|
+
}
|
|
392
|
+
if (options.whitelist !== void 0) {
|
|
393
|
+
if (typeof options.whitelist !== "string" && !Array.isArray(options.whitelist)) {
|
|
394
|
+
throw new TypeError("whitelist must be a string or an array of strings");
|
|
395
|
+
}
|
|
396
|
+
if (Array.isArray(options.whitelist)) {
|
|
397
|
+
for (const entry of options.whitelist) {
|
|
398
|
+
if (typeof entry !== "string") {
|
|
399
|
+
throw new TypeError("whitelist must be a string or an array of strings");
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
348
404
|
}
|
|
349
405
|
function validateOptions(options) {
|
|
350
406
|
validateSanitizeOptions(options);
|
|
@@ -352,6 +408,9 @@ function validateOptions(options) {
|
|
|
352
408
|
throw new TypeError("sources must be an array");
|
|
353
409
|
}
|
|
354
410
|
if (options.sources !== void 0) {
|
|
411
|
+
if (options.sources.length === 0) {
|
|
412
|
+
throw new TypeError("sources must contain at least one of 'query', 'body', 'params'");
|
|
413
|
+
}
|
|
355
414
|
for (const source of options.sources) {
|
|
356
415
|
if (!["query", "body", "params"].includes(source)) {
|
|
357
416
|
throw new TypeError("sources must only contain 'query', 'body', or 'params'");
|
|
@@ -361,8 +420,15 @@ function validateOptions(options) {
|
|
|
361
420
|
if (options.checkBodyContentType !== void 0 && !["urlencoded", "any", "none"].includes(options.checkBodyContentType)) {
|
|
362
421
|
throw new TypeError("checkBodyContentType must be 'urlencoded', 'any', or 'none'");
|
|
363
422
|
}
|
|
364
|
-
if (options.excludePaths !== void 0
|
|
365
|
-
|
|
423
|
+
if (options.excludePaths !== void 0) {
|
|
424
|
+
if (!Array.isArray(options.excludePaths)) {
|
|
425
|
+
throw new TypeError("excludePaths must be an array");
|
|
426
|
+
}
|
|
427
|
+
for (const entry of options.excludePaths) {
|
|
428
|
+
if (typeof entry !== "string") {
|
|
429
|
+
throw new TypeError("excludePaths must contain only strings");
|
|
430
|
+
}
|
|
431
|
+
}
|
|
366
432
|
}
|
|
367
433
|
if (options.logger !== void 0 && typeof options.logger !== "function") {
|
|
368
434
|
throw new TypeError("logger must be a function");
|
|
@@ -370,6 +436,12 @@ function validateOptions(options) {
|
|
|
370
436
|
if (options.onPollutionDetected !== void 0 && typeof options.onPollutionDetected !== "function") {
|
|
371
437
|
throw new TypeError("onPollutionDetected must be a function");
|
|
372
438
|
}
|
|
439
|
+
if (options.strict !== void 0 && typeof options.strict !== "boolean") {
|
|
440
|
+
throw new TypeError("strict must be a boolean");
|
|
441
|
+
}
|
|
442
|
+
if (options.logPollution !== void 0 && typeof options.logPollution !== "boolean") {
|
|
443
|
+
throw new TypeError("logPollution must be a boolean");
|
|
444
|
+
}
|
|
373
445
|
}
|
|
374
446
|
function hppx(options = {}) {
|
|
375
447
|
validateOptions(options);
|
|
@@ -394,9 +466,39 @@ function hppx(options = {}) {
|
|
|
394
466
|
const { isWhitelistedPath } = buildWhitelistHelpers(whitelistArr);
|
|
395
467
|
return function hppxMiddleware(req, res, next) {
|
|
396
468
|
try {
|
|
397
|
-
|
|
469
|
+
let pathForExclusion;
|
|
470
|
+
try {
|
|
471
|
+
pathForExclusion = req?.path;
|
|
472
|
+
} catch (pathErr) {
|
|
473
|
+
const message = `[hppx] Failed to read req.path during exclusion check; proceeding without path-based exclusion. Underlying error: ${pathErr instanceof Error ? pathErr.message : String(pathErr)}`;
|
|
474
|
+
if (logger) {
|
|
475
|
+
try {
|
|
476
|
+
logger(message);
|
|
477
|
+
} catch (_) {
|
|
478
|
+
console.warn(message);
|
|
479
|
+
}
|
|
480
|
+
} else {
|
|
481
|
+
console.warn(message);
|
|
482
|
+
}
|
|
483
|
+
pathForExclusion = void 0;
|
|
484
|
+
}
|
|
485
|
+
if (shouldExcludePath(pathForExclusion, excludePaths)) return next();
|
|
398
486
|
let anyPollutionDetected = false;
|
|
399
487
|
const allPollutedKeys = [];
|
|
488
|
+
const warned = /* @__PURE__ */ new Set();
|
|
489
|
+
const warn = (message) => {
|
|
490
|
+
if (warned.has(message)) return;
|
|
491
|
+
warned.add(message);
|
|
492
|
+
if (logger) {
|
|
493
|
+
try {
|
|
494
|
+
logger(message);
|
|
495
|
+
} catch (_) {
|
|
496
|
+
console.warn(message);
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
console.warn(message);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
400
502
|
for (const source of sources) {
|
|
401
503
|
if (!req || typeof req !== "object") break;
|
|
402
504
|
if (req[source] === void 0) continue;
|
|
@@ -409,7 +511,7 @@ function hppx(options = {}) {
|
|
|
409
511
|
const expandedPart = expandObjectPaths(part, maxKeyLength, maxDepth);
|
|
410
512
|
const pollutedKey = `${source}Polluted`;
|
|
411
513
|
const processedKey = `__hppxProcessed_${source}`;
|
|
412
|
-
const hasProcessedBefore =
|
|
514
|
+
const hasProcessedBefore = Object.prototype.hasOwnProperty.call(req, processedKey);
|
|
413
515
|
if (!hasProcessedBefore) {
|
|
414
516
|
const { cleaned, pollutedTree, pollutedKeys } = detectAndReduce(expandedPart, {
|
|
415
517
|
mergeStrategy,
|
|
@@ -420,9 +522,21 @@ function hppx(options = {}) {
|
|
|
420
522
|
trimValues,
|
|
421
523
|
preserveNull
|
|
422
524
|
});
|
|
423
|
-
setReqPropertySafe(req, source, cleaned);
|
|
424
|
-
setReqPropertySafe(req, pollutedKey, pollutedTree);
|
|
425
|
-
|
|
525
|
+
setReqPropertySafe(req, source, cleaned, warn);
|
|
526
|
+
setReqPropertySafe(req, pollutedKey, pollutedTree, warn);
|
|
527
|
+
try {
|
|
528
|
+
Object.defineProperty(req, processedKey, {
|
|
529
|
+
value: true,
|
|
530
|
+
writable: false,
|
|
531
|
+
configurable: false,
|
|
532
|
+
enumerable: false
|
|
533
|
+
});
|
|
534
|
+
} catch (_) {
|
|
535
|
+
try {
|
|
536
|
+
req[processedKey] = true;
|
|
537
|
+
} catch (_assignErr) {
|
|
538
|
+
}
|
|
539
|
+
}
|
|
426
540
|
const sourceData = req[source];
|
|
427
541
|
const pollutedData = req[pollutedKey];
|
|
428
542
|
if (isPlainObject(sourceData) && isPlainObject(pollutedData)) {
|
|
@@ -489,10 +603,8 @@ function hppx(options = {}) {
|
|
|
489
603
|
try {
|
|
490
604
|
logger(error);
|
|
491
605
|
} catch (logErr) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
console.error("[hppx] Original error:", error);
|
|
495
|
-
}
|
|
606
|
+
console.error("[hppx] Logger failed:", logErr);
|
|
607
|
+
console.error("[hppx] Original error:", error);
|
|
496
608
|
}
|
|
497
609
|
}
|
|
498
610
|
return next(error);
|
|
@@ -504,6 +616,7 @@ function hppx(options = {}) {
|
|
|
504
616
|
DANGEROUS_KEYS,
|
|
505
617
|
DEFAULT_SOURCES,
|
|
506
618
|
DEFAULT_STRATEGY,
|
|
619
|
+
__resetPathSegmentCache,
|
|
507
620
|
sanitize
|
|
508
621
|
});
|
|
509
622
|
if (module.exports.default) { module.exports = Object.assign(module.exports.default, module.exports); }
|