Allow configuration of maxDepthOfQuery
https://github.com/strongloop/loopback-datasource-juggler/issues/1651
This commit is contained in:
parent
b4d0cf54a8
commit
41d5f20fff
|
@ -1684,8 +1684,8 @@ DataAccessObject._sanitizeQuery = function(query, options) {
|
||||||
prohibitHiddenPropertiesInQuery = true;
|
prohibitHiddenPropertiesInQuery = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prohibitHiddenPropertiesInQuery)
|
// See https://github.com/strongloop/loopback-datasource-juggler/issues/1651
|
||||||
console.log(prohibitHiddenPropertiesInQuery);
|
var maxDepthOfQuery = (+this._getSetting('maxDepthOfQuery')) || 12;
|
||||||
|
|
||||||
var prohibitedKeys = [];
|
var prohibitedKeys = [];
|
||||||
// Check violation of keys
|
// Check violation of keys
|
||||||
|
@ -1697,6 +1697,7 @@ DataAccessObject._sanitizeQuery = function(query, options) {
|
||||||
}
|
}
|
||||||
return sanitizeQueryOrData(query,
|
return sanitizeQueryOrData(query,
|
||||||
Object.assign({
|
Object.assign({
|
||||||
|
maxDepth: maxDepthOfQuery,
|
||||||
prohibitedKeys: prohibitedKeys,
|
prohibitedKeys: prohibitedKeys,
|
||||||
normalizeUndefinedInQuery: normalizeUndefinedInQuery,
|
normalizeUndefinedInQuery: normalizeUndefinedInQuery,
|
||||||
}, options));
|
}, options));
|
||||||
|
|
15
lib/utils.js
15
lib/utils.js
|
@ -336,18 +336,25 @@ function sanitizeQuery(query, options) {
|
||||||
const prohibitedKeys = options.prohibitedKeys;
|
const prohibitedKeys = options.prohibitedKeys;
|
||||||
const offendingKeys = [];
|
const offendingKeys = [];
|
||||||
const normalizeUndefinedInQuery = options.normalizeUndefinedInQuery;
|
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
|
// WARNING: [rfeng] Use map() will cause mongodb to produce invalid BSON
|
||||||
// as traverse doesn't transform the ObjectId correctly
|
// as traverse doesn't transform the ObjectId correctly
|
||||||
const result = traverse(query).forEach(function(x) {
|
const result = traverse(query).forEach(function(x) {
|
||||||
/**
|
/**
|
||||||
* Security risk if the client passes in a very deep where object
|
* Security risk if the client passes in a very deep where object
|
||||||
*/
|
*/
|
||||||
if (this.level > maxDepth || this.circular) {
|
if (this.circular) {
|
||||||
const msg = g.f('The query object is too deep or circular');
|
const msg = g.f('The query object is circular');
|
||||||
const err = new Error(msg);
|
const err = new Error(msg);
|
||||||
err.statusCode = 400;
|
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;
|
throw err;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -257,6 +257,41 @@ describe('ModelDefinition class', function() {
|
||||||
done();
|
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() {
|
it('should serialize protected properties into JSON', function() {
|
||||||
var ProtectedModel = memory.createModel('protected', {}, {
|
var ProtectedModel = memory.createModel('protected', {}, {
|
||||||
protected: ['protectedProperty'],
|
protected: ['protectedProperty'],
|
||||||
|
|
|
@ -88,18 +88,18 @@ describe('util.sanitizeQuery', function() {
|
||||||
var q7 = {where: {x: 1}};
|
var q7 = {where: {x: 1}};
|
||||||
q7.where.y = q7;
|
q7.where.y = q7;
|
||||||
(function() { sanitizeQuery(q7); }).should.throw(
|
(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:
|
var q8 = {where: {and: [{and: [{and: [{and: [{and: [{and:
|
||||||
[{and: [{and: [{and: [{x: 1}]}]}]}]}]}]}]}]}]}};
|
[{and: [{and: [{and: [{x: 1}]}]}]}]}]}]}]}]}]}};
|
||||||
(function() { sanitizeQuery(q8); }).should.throw(
|
(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}]}]}]}]}};
|
var q9 = {where: {and: [{and: [{and: [{and: [{x: 1}]}]}]}]}};
|
||||||
(function() { sanitizeQuery(q8, {maxDepth: 4}); }).should.throw(
|
(function() { sanitizeQuery(q8, {maxDepth: 4}); }).should.throw(
|
||||||
/The query object is too deep or circular/
|
/The query object exceeds maximum depth 4/
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue