@contrast/route-coverage 1.54.0 → 1.55.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.
@@ -31,6 +31,7 @@ const {
31
31
  } = require('@contrast/common');
32
32
  const Core = require('@contrast/core/lib/ioc/core');
33
33
 
34
+ const MAX_REPEATED_TRAVERSALS = 10;
34
35
  const METHODS = [
35
36
  'all',
36
37
  'get',
@@ -260,8 +261,25 @@ class ExpressInstrumentation {
260
261
  post(data) {
261
262
  const { result } = data;
262
263
  if (!result || !data._store || !data[kMetaKey]?.template) return;
264
+
263
265
  // if the layer matches, we know to push corresponding path to store's template segments.
264
266
  // we pop this value from the array in hook to all `next` callbacks below.
267
+
268
+ // special case if the layer has a route instance (.use wasn't called to create layer)
269
+ if (data.obj.route) {
270
+ // the layer might match the path, but the route might not support the method.
271
+ // in this case don't capture the current template segment.
272
+ const store = core.scopes.sources.getStore();
273
+ if (
274
+ store.sourceInfo?.method &&
275
+ data.obj.route?.methods &&
276
+ !data.obj.route.methods[store.sourceInfo.method] &&
277
+ !data.obj.route.methods._all
278
+ ) {
279
+ return;
280
+ }
281
+ }
282
+
265
283
  data._store.templateSegments.push(data[kMetaKey].template);
266
284
  }
267
285
  });
@@ -423,17 +441,24 @@ class ExpressInstrumentation {
423
441
 
424
442
  // only visit Layer instances
425
443
  const maybeLayer = target[key];
426
- if (
427
- maybeLayer?.constructor?.name == 'Layer' &&
428
- !maybeLayer?.stack?.length
429
- ) {
430
- let _data = data.get(maybeLayer);
431
-
432
- if (!_data) {
433
- _data = { paths: [] };
434
- data.set(maybeLayer, _data);
435
- }
436
444
 
445
+ const _data = data.get(maybeLayer) ?? { paths: [], visitCount: 0 };
446
+ data.set(maybeLayer, _data);
447
+
448
+ // track number of times we've visited a certain member across all paths.
449
+ _data.visitCount++;
450
+ _data.paths.push([...path]); // copy because path argument mutates
451
+
452
+ // if we've exceeded a "reasonable" number of visits to a certain member
453
+ // it's likely we've encountered circular references and should stop
454
+ // traversing that path to prevent a stack overflow.
455
+ if (_data.visitCount > MAX_REPEATED_TRAVERSALS) {
456
+ path.pop();
457
+ continue loopKeys;
458
+ }
459
+
460
+ // Only execute the callback on valid Layer objects.
461
+ if (maybeLayer?.constructor?.name == 'Layer' && !maybeLayer?.stack?.length) {
437
462
  // you can mount a router on itself
438
463
  // prevent infinitely recursing into self-mounted routers
439
464
  for (const visitedPath of _data.paths) {
@@ -447,8 +472,6 @@ class ExpressInstrumentation {
447
472
  }
448
473
  }
449
474
 
450
- _data.paths.push([...path]); // copy because path argument mutates
451
-
452
475
  const halt = cb(path, key, maybeLayer, target) === false;
453
476
  if (halt) return;
454
477
  }
@@ -123,7 +123,7 @@ module.exports = function init(core) {
123
123
  * and prepareRoute({ options: { method, url, options, handler }})
124
124
  */
125
125
  [
126
- { version: '>=3 <4.1.0', routeObj: false },
126
+ { version: '>=4 <4.1.0', routeObj: false },
127
127
  { version: '>=4.1.0 <6', routeObj: true },
128
128
  ].forEach(({ version, routeObj }) => {
129
129
  // See ../utils/methods
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/route-coverage",
3
- "version": "1.54.0",
3
+ "version": "1.55.0",
4
4
  "description": "Handles route discovery and observation",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -20,15 +20,15 @@
20
20
  "test": "bash ../scripts/test.sh"
21
21
  },
22
22
  "dependencies": {
23
- "@contrast/common": "1.40.0",
24
- "@contrast/config": "1.56.0",
25
- "@contrast/core": "1.61.0",
26
- "@contrast/dep-hooks": "1.30.0",
23
+ "@contrast/common": "1.41.0",
24
+ "@contrast/config": "1.57.0",
25
+ "@contrast/core": "1.62.0",
26
+ "@contrast/dep-hooks": "1.31.0",
27
27
  "@contrast/fn-inspect": "^5.0.2",
28
- "@contrast/logger": "1.34.0",
29
- "@contrast/patcher": "1.33.0",
30
- "@contrast/rewriter": "1.38.0",
31
- "@contrast/scopes": "1.31.0",
28
+ "@contrast/logger": "1.35.0",
29
+ "@contrast/patcher": "1.34.0",
30
+ "@contrast/rewriter": "1.39.0",
31
+ "@contrast/scopes": "1.32.0",
32
32
  "semver": "^7.6.0"
33
33
  }
34
34
  }