@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/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 isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
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 (isPlainObject(value)) {
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 (!isPlainObject(value)) return false;
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 (isPlainObject(value)) {
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 globalBeforeMws = [...config.globalMiddleware ?? []].map(
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
- ...globalBeforeMws,
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(eventName, handler) {
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(eventName, payload, rooms, metadata) {
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