diff --git a/lib/utils.js b/lib/utils.js index 7620dba8..b1e85482 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -302,6 +302,19 @@ function selectFields(fields) { }; } +function isProhibited(key, prohibitedKeys) { + if (!prohibitedKeys || !prohibitedKeys.length) return false; + if (typeof key !== 'string') { + return false; + } + for (var k of prohibitedKeys) { + if (k === key) return true; + // x.secret, secret.y, or x.secret.y + if (key.split('.').indexOf(k) !== -1) return true; + } + return false; +} + /** * Sanitize the query object * @param query {object} The query object @@ -341,7 +354,7 @@ function sanitizeQuery(query, options) { * Make sure prohibited keys are removed from the query to prevent * sensitive values from being guessed */ - if (prohibitedKeys && prohibitedKeys.indexOf(this.key) !== -1) { + if (isProhibited(this.key, prohibitedKeys)) { offendingKeys.push(this.key); this.remove(); return; diff --git a/test/loopback-dl.test.js b/test/loopback-dl.test.js index befc6816..00694d55 100644 --- a/test/loopback-dl.test.js +++ b/test/loopback-dl.test.js @@ -394,7 +394,6 @@ describe('DataSource define model', function() { User.create({name: 'Jeff'}, function(err, data) { if (err) { - console.log(err); return; } var post = data.posts.build({title: 'My Post'}); diff --git a/test/model-definition.test.js b/test/model-definition.test.js index 7298f2b1..f49ae8ae 100644 --- a/test/model-definition.test.js +++ b/test/model-definition.test.js @@ -395,7 +395,10 @@ describe('ModelDefinition class', function() { */ function givenChildren(hiddenProps) { hiddenProps = hiddenProps || {hidden: ['secret']}; - Child = memory.createModel('child', {}, hiddenProps); + Child = memory.createModel('child', { + name: String, + secret: String, + }, hiddenProps); return Child.create([{ name: 'childA', secret: 'secret', @@ -412,6 +415,64 @@ describe('ModelDefinition class', function() { } }); + describe('hidden nested properties', function() { + var Child; + beforeEach(givenChildren); + + it('should be removed if used in where as a composite key - x.secret', function() { + return Child.find({ + where: {'x.secret': 'guess'}, + }).then(assertHiddenPropertyIsIgnored); + }); + + it('should be removed if used in where as a composite key - secret.y', function() { + return Child.find({ + where: {'secret.y': 'guess'}, + }).then(assertHiddenPropertyIsIgnored); + }); + + it('should be removed if used in where as a composite key - a.secret.b', function() { + return Child.find({ + where: {'a.secret.b': 'guess'}, + }).then(assertHiddenPropertyIsIgnored); + }); + + function givenChildren() { + var hiddenProps = {hidden: ['secret']}; + Child = memory.createModel('child', { + name: String, + x: { + secret: String, + }, + secret: { + y: String, + }, + a: { + secret: { + b: String, + }, + }, + }, hiddenProps); + return Child.create([{ + name: 'childA', + x: {secret: 'secret'}, + secret: {y: 'secret'}, + a: {secret: {b: 'secret'}}, + }, { + name: 'childB', + x: {secret: 'guess'}, + secret: {y: 'guess'}, + a: {secret: {b: 'guess'}}, + }]); + } + + function assertHiddenPropertyIsIgnored(children) { + // All children are found whether the `secret` condition matches or not + // as the condition is removed because it's hidden + children.length.should.equal(2); + } + }); + function assertParentIncludeChildren(parents) { parents[0].toJSON().children.length.should.equal(1); }