@emeryld/rrroutes-server 2.4.8 → 2.5.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/README.md +37 -6
- package/dist/index.cjs +159 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +157 -8
- package/dist/index.js.map +1 -1
- package/dist/routesV3.server.d.ts +29 -8
- package/dist/routesV3.server.sanitize.d.ts +71 -0
- package/dist/sockets/socket.server.index.d.ts +11 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -8,6 +8,140 @@ import {
|
|
|
8
8
|
lowProfileParse
|
|
9
9
|
} from "@emeryld/rrroutes-contract";
|
|
10
10
|
import multer from "multer";
|
|
11
|
+
|
|
12
|
+
// src/routesV3.server.sanitize.ts
|
|
13
|
+
var defaultTargets = ["params", "query", "body"];
|
|
14
|
+
var defaultBlockedKeys = ["__proto__", "prototype", "constructor"];
|
|
15
|
+
var defaultMaxDepth = 20;
|
|
16
|
+
var nullBytePattern = /\u0000/g;
|
|
17
|
+
var isPlainObject = (value) => {
|
|
18
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
19
|
+
const proto = Object.getPrototypeOf(value);
|
|
20
|
+
return proto === Object.prototype || proto === null;
|
|
21
|
+
};
|
|
22
|
+
var normalizeOptions = (options) => {
|
|
23
|
+
return {
|
|
24
|
+
targets: new Set(options.targets ?? defaultTargets),
|
|
25
|
+
trimStrings: options.trimStrings ?? false,
|
|
26
|
+
stripNullBytes: options.stripNullBytes ?? true,
|
|
27
|
+
stripPrototypePollutionKeys: options.stripPrototypePollutionKeys ?? true,
|
|
28
|
+
blockedKeys: new Set(options.blockedKeys ?? defaultBlockedKeys),
|
|
29
|
+
maxDepth: options.maxDepth ?? defaultMaxDepth,
|
|
30
|
+
customSanitizer: options.customSanitizer
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
var applyCustomSanitizer = (value, options, context) => {
|
|
34
|
+
if (!options.customSanitizer) return value;
|
|
35
|
+
return options.customSanitizer(value, context);
|
|
36
|
+
};
|
|
37
|
+
var sanitizeString = (value, options) => {
|
|
38
|
+
let next = value;
|
|
39
|
+
if (options.stripNullBytes && next.includes("\0")) {
|
|
40
|
+
next = next.replace(nullBytePattern, "");
|
|
41
|
+
}
|
|
42
|
+
if (options.trimStrings) {
|
|
43
|
+
next = next.trim();
|
|
44
|
+
}
|
|
45
|
+
return next;
|
|
46
|
+
};
|
|
47
|
+
var sanitizeValue = (value, options, depth, seen, req, target, path) => {
|
|
48
|
+
const context = {
|
|
49
|
+
req,
|
|
50
|
+
target,
|
|
51
|
+
path,
|
|
52
|
+
depth
|
|
53
|
+
};
|
|
54
|
+
if (depth > options.maxDepth) {
|
|
55
|
+
return applyCustomSanitizer(value, options, context);
|
|
56
|
+
}
|
|
57
|
+
if (typeof value === "string") {
|
|
58
|
+
const sanitized = sanitizeString(value, options);
|
|
59
|
+
return applyCustomSanitizer(sanitized, options, context);
|
|
60
|
+
}
|
|
61
|
+
if (value && typeof value === "object" && seen.has(value)) {
|
|
62
|
+
return applyCustomSanitizer(value, options, context);
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
seen.add(value);
|
|
66
|
+
const next = value.map(
|
|
67
|
+
(entry, index) => sanitizeValue(entry, options, depth + 1, seen, req, target, [
|
|
68
|
+
...path,
|
|
69
|
+
index
|
|
70
|
+
])
|
|
71
|
+
);
|
|
72
|
+
seen.delete(value);
|
|
73
|
+
return applyCustomSanitizer(next, options, context);
|
|
74
|
+
}
|
|
75
|
+
if (!isPlainObject(value)) {
|
|
76
|
+
return applyCustomSanitizer(value, options, context);
|
|
77
|
+
}
|
|
78
|
+
seen.add(value);
|
|
79
|
+
const source = value;
|
|
80
|
+
const objectTarget = Object.getPrototypeOf(source) === null ? /* @__PURE__ */ Object.create(null) : {};
|
|
81
|
+
for (const [key, entry] of Object.entries(source)) {
|
|
82
|
+
if (options.stripPrototypePollutionKeys && options.blockedKeys.has(key)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
;
|
|
86
|
+
objectTarget[key] = sanitizeValue(
|
|
87
|
+
entry,
|
|
88
|
+
options,
|
|
89
|
+
depth + 1,
|
|
90
|
+
seen,
|
|
91
|
+
req,
|
|
92
|
+
context.target,
|
|
93
|
+
[...path, key]
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
seen.delete(value);
|
|
97
|
+
return applyCustomSanitizer(objectTarget, options, context);
|
|
98
|
+
};
|
|
99
|
+
var createRequestSanitizationMiddleware = (options = {}) => {
|
|
100
|
+
const normalized = normalizeOptions(options);
|
|
101
|
+
return (req, _res, next) => {
|
|
102
|
+
try {
|
|
103
|
+
if (normalized.targets.has("params") && req.params) {
|
|
104
|
+
req.params = sanitizeValue(
|
|
105
|
+
req.params,
|
|
106
|
+
normalized,
|
|
107
|
+
0,
|
|
108
|
+
/* @__PURE__ */ new WeakSet(),
|
|
109
|
+
req,
|
|
110
|
+
"params",
|
|
111
|
+
[]
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
if (normalized.targets.has("query") && req.query) {
|
|
115
|
+
req.query = sanitizeValue(
|
|
116
|
+
req.query,
|
|
117
|
+
normalized,
|
|
118
|
+
0,
|
|
119
|
+
/* @__PURE__ */ new WeakSet(),
|
|
120
|
+
req,
|
|
121
|
+
"query",
|
|
122
|
+
[]
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
if (normalized.targets.has("body") && req.body !== void 0) {
|
|
126
|
+
req.body = sanitizeValue(
|
|
127
|
+
req.body,
|
|
128
|
+
normalized,
|
|
129
|
+
0,
|
|
130
|
+
/* @__PURE__ */ new WeakSet(),
|
|
131
|
+
req,
|
|
132
|
+
"body",
|
|
133
|
+
[]
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
next();
|
|
137
|
+
} catch (err) {
|
|
138
|
+
next(err);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
var requestSanitizationMiddleware = createRequestSanitizationMiddleware();
|
|
143
|
+
|
|
144
|
+
// src/routesV3.server.ts
|
|
11
145
|
var serverDebugEventTypes = [
|
|
12
146
|
"register",
|
|
13
147
|
"request",
|
|
@@ -41,12 +175,12 @@ function createServerDebugEmitter(option) {
|
|
|
41
175
|
}
|
|
42
176
|
return disabled;
|
|
43
177
|
}
|
|
44
|
-
var
|
|
178
|
+
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
179
|
var decodeJsonLikeQueryValue = (value) => {
|
|
46
180
|
if (Array.isArray(value)) {
|
|
47
181
|
return value.map((entry) => decodeJsonLikeQueryValue(entry));
|
|
48
182
|
}
|
|
49
|
-
if (
|
|
183
|
+
if (isPlainObject2(value)) {
|
|
50
184
|
const next = {};
|
|
51
185
|
for (const [key, child] of Object.entries(value)) {
|
|
52
186
|
next[key] = decodeJsonLikeQueryValue(child);
|
|
@@ -70,7 +204,7 @@ var REQUEST_PAYLOAD_SYMBOL = /* @__PURE__ */ Symbol.for(
|
|
|
70
204
|
"typedLeaves.requestPayload"
|
|
71
205
|
);
|
|
72
206
|
function isMulterFile(value) {
|
|
73
|
-
if (!
|
|
207
|
+
if (!isPlainObject2(value)) return false;
|
|
74
208
|
const candidate = value;
|
|
75
209
|
return typeof candidate.fieldname === "string";
|
|
76
210
|
}
|
|
@@ -86,7 +220,7 @@ function collectMulterFiles(req) {
|
|
|
86
220
|
files.push(value);
|
|
87
221
|
return;
|
|
88
222
|
}
|
|
89
|
-
if (
|
|
223
|
+
if (isPlainObject2(value)) {
|
|
90
224
|
Object.values(value).forEach(pushValue);
|
|
91
225
|
}
|
|
92
226
|
};
|
|
@@ -212,9 +346,12 @@ function createRRRoute(router, config) {
|
|
|
212
346
|
if (!isVerbose || !details) return event;
|
|
213
347
|
return { ...event, ...details };
|
|
214
348
|
};
|
|
215
|
-
const
|
|
349
|
+
const middlewareConfig = config.middleware ?? {};
|
|
350
|
+
const postCtxMws = [...middlewareConfig.postCtx ?? []].map(
|
|
216
351
|
(mw) => adaptCtxMw(mw)
|
|
217
352
|
);
|
|
353
|
+
const preCtxMws = [...middlewareConfig.preCtx ?? []];
|
|
354
|
+
const sanitizerMw = middlewareConfig.sanitizer === void 0 ? void 0 : typeof middlewareConfig.sanitizer === "function" ? middlewareConfig.sanitizer : createRequestSanitizationMiddleware(middlewareConfig.sanitizer);
|
|
218
355
|
const registered = getRegisteredRouteStore(router);
|
|
219
356
|
const getMulterOptions = (fields) => {
|
|
220
357
|
if (!fields || fields.length === 0) return void 0;
|
|
@@ -376,9 +513,11 @@ function createRRRoute(router, config) {
|
|
|
376
513
|
}
|
|
377
514
|
};
|
|
378
515
|
const before = [
|
|
516
|
+
...sanitizerMw ? [sanitizerMw] : [],
|
|
517
|
+
...preCtxMws,
|
|
379
518
|
resolvePayloadMw,
|
|
380
519
|
ctxMw,
|
|
381
|
-
...
|
|
520
|
+
...postCtxMws,
|
|
382
521
|
...routeSpecific
|
|
383
522
|
];
|
|
384
523
|
const wrapped = async (req, res, next) => {
|
|
@@ -1080,7 +1219,10 @@ function createSocketConnections(io, events, opts) {
|
|
|
1080
1219
|
});
|
|
1081
1220
|
io.on("connection", builtInConnectionListener);
|
|
1082
1221
|
const conn = {
|
|
1083
|
-
on(
|
|
1222
|
+
on({
|
|
1223
|
+
eventName,
|
|
1224
|
+
handler
|
|
1225
|
+
}) {
|
|
1084
1226
|
const socketListeners = /* @__PURE__ */ new WeakMap();
|
|
1085
1227
|
const connectionListener = (socket) => {
|
|
1086
1228
|
const wrapped = async (raw) => {
|
|
@@ -1189,7 +1331,12 @@ function createSocketConnections(io, events, opts) {
|
|
|
1189
1331
|
off(eventName) {
|
|
1190
1332
|
removeAllForEvent(String(eventName));
|
|
1191
1333
|
},
|
|
1192
|
-
emitAny(
|
|
1334
|
+
emitAny({
|
|
1335
|
+
eventName,
|
|
1336
|
+
payload,
|
|
1337
|
+
rooms,
|
|
1338
|
+
metadata
|
|
1339
|
+
}) {
|
|
1193
1340
|
const targets = toArray2(rooms);
|
|
1194
1341
|
if (Object.prototype.hasOwnProperty.call(events, eventName)) {
|
|
1195
1342
|
emitToTargets(
|
|
@@ -1385,9 +1532,11 @@ export {
|
|
|
1385
1532
|
keyOf2 as contractKeyOf,
|
|
1386
1533
|
createConnectionLoggingMiddleware,
|
|
1387
1534
|
createRRRoute,
|
|
1535
|
+
createRequestSanitizationMiddleware,
|
|
1388
1536
|
createSocketConnections,
|
|
1389
1537
|
defineControllers,
|
|
1390
1538
|
getCtx,
|
|
1539
|
+
requestSanitizationMiddleware,
|
|
1391
1540
|
warnMissingControllers
|
|
1392
1541
|
};
|
|
1393
1542
|
//# sourceMappingURL=index.js.map
|