Allow configuration of maxDepthOfQuery

https://github.com/strongloop/loopback-datasource-juggler/issues/1651
This commit is contained in:
Raymond Feng 2018-10-30 12:14:52 -07:00
parent b4d0cf54a8
commit 41d5f20fff
4 changed files with 52 additions and 9 deletions

View File

@ -1684,8 +1684,8 @@ DataAccessObject._sanitizeQuery = function(query, options) {
prohibitHiddenPropertiesInQuery = true;
}
if (!prohibitHiddenPropertiesInQuery)
console.log(prohibitHiddenPropertiesInQuery);
// See https://github.com/strongloop/loopback-datasource-juggler/issues/1651
var maxDepthOfQuery = (+this._getSetting('maxDepthOfQuery')) || 12;
var prohibitedKeys = [];
// Check violation of keys
@ -1697,6 +1697,7 @@ DataAccessObject._sanitizeQuery = function(query, options) {
}
return sanitizeQueryOrData(query,
Object.assign({
maxDepth: maxDepthOfQuery,
prohibitedKeys: prohibitedKeys,
normalizeUndefinedInQuery: normalizeUndefinedInQuery,
}, options));

View File

@ -336,18 +336,25 @@ function sanitizeQuery(query, options) {
const prohibitedKeys = options.prohibitedKeys;
const offendingKeys = [];
const normalizeUndefinedInQuery = options.normalizeUndefinedInQuery;
const maxDepth = options.maxDepth || 10;
const maxDepth = options.maxDepth || 12;
// WARNING: [rfeng] Use map() will cause mongodb to produce invalid BSON
// as traverse doesn't transform the ObjectId correctly
const result = traverse(query).forEach(function(x) {
/**
* Security risk if the client passes in a very deep where object
*/
if (this.level > maxDepth || this.circular) {
const msg = g.f('The query object is too deep or circular');
if (this.circular) {
const msg = g.f('The query object is circular');
const err = new Error(msg);
err.statusCode = 400;
err.code = 'WHERE_OBJECT_TOO_DEEP';
err.code = 'QUERY_OBJECT_IS_CIRCULAR';
throw err;
}
if (this.level > maxDepth) {
const msg = g.f('The query object exceeds maximum depth %d', maxDepth);
const err = new Error(msg);
err.statusCode = 400;
err.code = 'QUERY_OBJECT_TOO_DEEP';
throw err;
}
/**

View File

@ -257,6 +257,41 @@ describe('ModelDefinition class', function() {
done();
});
describe('maxDepthOfQuery', function() {
it('should report errors for deep query than maxDepthOfQuery', function(done) {
var MyModel = memory.createModel('my-model', {}, {
maxDepthOfQuery: 5,
});
var filter = givenComplexFilter();
MyModel.find(filter, function(err) {
should.exist(err);
err.message.should.match('The query object exceeds maximum depth 5');
done();
});
});
it('should honor maxDepthOfQuery setting', function(done) {
var MyModel = memory.createModel('my-model', {}, {
maxDepthOfQuery: 20,
});
var filter = givenComplexFilter();
MyModel.find(filter, function(err) {
should.not.exist(err);
done();
});
});
function givenComplexFilter() {
var filter = {where: {and: [{and: [{and: [{and: [{and: [{and:
[{and: [{and: [{and: [{x: 1}]}]}]}]}]}]}]}]}]}};
return filter;
}
});
it('should serialize protected properties into JSON', function() {
var ProtectedModel = memory.createModel('protected', {}, {
protected: ['protectedProperty'],

View File

@ -88,18 +88,18 @@ describe('util.sanitizeQuery', function() {
var q7 = {where: {x: 1}};
q7.where.y = q7;
(function() { sanitizeQuery(q7); }).should.throw(
/The query object is too deep or circular/
/The query object is circular/
);
var q8 = {where: {and: [{and: [{and: [{and: [{and: [{and:
[{and: [{and: [{and: [{x: 1}]}]}]}]}]}]}]}]}]}};
(function() { sanitizeQuery(q8); }).should.throw(
/The query object is too deep or circular/
/The query object exceeds maximum depth 12/
);
var q9 = {where: {and: [{and: [{and: [{and: [{x: 1}]}]}]}]}};
(function() { sanitizeQuery(q8, {maxDepth: 4}); }).should.throw(
/The query object is too deep or circular/
/The query object exceeds maximum depth 4/
);
});