mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
Merge pull request #16402 from nestjs/fix/pattern-max-depth-keys
fix(microservices): introuduce max pattern depth and object complexity
This commit is contained in:
@@ -120,4 +120,22 @@ describe('transformPatternToRoute', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when gets value exceeding max depth or max keys', () => {
|
||||||
|
it('should return special string indicating the limit was reached', () => {
|
||||||
|
const deepNestedPattern = {
|
||||||
|
a: { b: { c: { d: { e: { f: 'too deep' } } } } },
|
||||||
|
};
|
||||||
|
const tooManyKeysPattern = Object.fromEntries(
|
||||||
|
Array.from({ length: 25 }, (_, i) => [`key${i}`, `value${i}`]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(transformPatternToRoute(deepNestedPattern)).to.be.equal(
|
||||||
|
'{"a":{"b":{"c":{"d":{"e":"[MAX_DEPTH_REACHED]"}}}}}',
|
||||||
|
);
|
||||||
|
expect(transformPatternToRoute(tooManyKeysPattern)).to.be.equal(
|
||||||
|
'"[TOO_MANY_KEYS]"',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,43 +1,60 @@
|
|||||||
import {
|
import {
|
||||||
|
isNumber,
|
||||||
isObject,
|
isObject,
|
||||||
isString,
|
isString,
|
||||||
isNumber,
|
|
||||||
} from '@nestjs/common/utils/shared.utils';
|
} from '@nestjs/common/utils/shared.utils';
|
||||||
import { MsPattern } from '../interfaces';
|
import { MsPattern } from '../interfaces';
|
||||||
|
|
||||||
|
const DEFAULT_MAX_DEPTH = 5;
|
||||||
|
const DEFAULT_MAX_KEYS = 20;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the Pattern to Route.
|
* Transforms the Pattern to Route safely.
|
||||||
* 1. If Pattern is a `string`, it will be returned as it is.
|
|
||||||
* 2. If Pattern is a `number`, it will be converted to `string`.
|
|
||||||
* 3. If Pattern is a `JSON` object, it will be transformed to Route. For that end,
|
|
||||||
* the function will sort properties of `JSON` Object and creates `route` string
|
|
||||||
* according to the following template:
|
|
||||||
* <key1>:<value1>/<key2>:<value2>/.../<keyN>:<valueN>
|
|
||||||
*
|
*
|
||||||
* @param {MsPattern} pattern - client pattern
|
* @param pattern - client pattern
|
||||||
|
* @param depth - current recursion depth
|
||||||
|
* @param maxDepth - maximum allowed recursion depth
|
||||||
|
* @param maxKeys - maximum allowed keys per object
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
export function transformPatternToRoute(pattern: MsPattern): string {
|
export function transformPatternToRoute(
|
||||||
|
pattern: MsPattern,
|
||||||
|
depth = 0,
|
||||||
|
maxDepth = DEFAULT_MAX_DEPTH,
|
||||||
|
maxKeys = DEFAULT_MAX_KEYS,
|
||||||
|
): string {
|
||||||
|
// Prevent excessively deep recursion
|
||||||
|
if (depth > maxDepth) {
|
||||||
|
return '"[MAX_DEPTH_REACHED]"';
|
||||||
|
}
|
||||||
|
|
||||||
if (isString(pattern) || isNumber(pattern)) {
|
if (isString(pattern) || isNumber(pattern)) {
|
||||||
return `${pattern}`;
|
return `${pattern}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isObject(pattern)) {
|
if (!isObject(pattern)) {
|
||||||
return pattern;
|
return `"${String(pattern)}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedKeys = Object.keys(pattern).sort((a, b) =>
|
const keys = Object.keys(pattern);
|
||||||
('' + a).localeCompare(b),
|
|
||||||
);
|
// Limit number of keys to prevent huge objects
|
||||||
|
if (keys.length > maxKeys) {
|
||||||
|
return '"[TOO_MANY_KEYS]"';
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedKeys = keys.sort((a, b) => ('' + a).localeCompare(b));
|
||||||
|
|
||||||
// Creates the array of Pattern params from sorted keys and their corresponding values
|
|
||||||
const sortedPatternParams = sortedKeys.map(key => {
|
const sortedPatternParams = sortedKeys.map(key => {
|
||||||
let partialRoute = `"${key}":`;
|
const value = pattern[key];
|
||||||
partialRoute += isString(pattern[key])
|
const partialRoute = `"${key}":${transformPatternToRoute(
|
||||||
? `"${transformPatternToRoute(pattern[key])}"`
|
value,
|
||||||
: transformPatternToRoute(pattern[key]);
|
depth + 1,
|
||||||
|
maxDepth,
|
||||||
|
maxKeys,
|
||||||
|
)}`;
|
||||||
return partialRoute;
|
return partialRoute;
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = sortedPatternParams.join(',');
|
return `{${sortedPatternParams.join(',')}}`;
|
||||||
return `{${route}}`;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user