From b343de0c7054135558b1b9b5cd9d150bfe03a2a6 Mon Sep 17 00:00:00 2001 From: awgeorge Date: Mon, 28 Jan 2019 07:50:21 +0000 Subject: [PATCH] Set default protectedFields and remove previous filter logic --- spec/MongoSchemaCollectionAdapter.spec.js | 2 + spec/ParseLiveQueryServer.spec.js | 4 ++ spec/Schema.spec.js | 70 +++++++++++++++++++ spec/schemas.spec.js | 5 ++ .../Storage/Mongo/MongoSchemaCollection.js | 2 + .../Postgres/PostgresStorageAdapter.js | 2 + src/Controllers/SchemaController.js | 6 +- src/RestQuery.js | 14 +--- 8 files changed, 91 insertions(+), 14 deletions(-) diff --git a/spec/MongoSchemaCollectionAdapter.spec.js b/spec/MongoSchemaCollectionAdapter.spec.js index 2c5e889a..d8c84e9a 100644 --- a/spec/MongoSchemaCollectionAdapter.spec.js +++ b/spec/MongoSchemaCollectionAdapter.spec.js @@ -23,6 +23,7 @@ describe('MongoSchemaCollection', () => { create: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, indexes: { name1: { deviceToken: 1 }, @@ -72,6 +73,7 @@ describe('MongoSchemaCollection', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, indexes: { name1: { deviceToken: 1 }, diff --git a/spec/ParseLiveQueryServer.spec.js b/spec/ParseLiveQueryServer.spec.js index e2870b14..15ba12a0 100644 --- a/spec/ParseLiveQueryServer.spec.js +++ b/spec/ParseLiveQueryServer.spec.js @@ -257,6 +257,7 @@ describe('ParseLiveQueryServer', function() { find: {}, update: {}, delete: { '*': true }, + protectedFields: {}, }); expect(deleteSpy).toHaveBeenCalled(); @@ -270,6 +271,7 @@ describe('ParseLiveQueryServer', function() { find: {}, update: {}, delete: { '*': true }, + protectedFields: {}, }); done(); }) @@ -1920,6 +1922,7 @@ describe('LiveQueryController', () => { find: {}, update: {}, delete: { '*': true }, + protectedFields: {}, }); expect(deleteSpy).toHaveBeenCalled(); @@ -1933,6 +1936,7 @@ describe('LiveQueryController', () => { find: {}, update: {}, delete: { '*': true }, + protectedFields: {}, }); done(); }) diff --git a/spec/Schema.spec.js b/spec/Schema.spec.js index 5a7c9036..b949dd7f 100644 --- a/spec/Schema.spec.js +++ b/spec/Schema.spec.js @@ -320,6 +320,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); @@ -338,6 +339,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }; config.database.loadSchema().then(schema => { schema @@ -461,6 +463,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); @@ -653,6 +656,68 @@ describe('SchemaController', () => { }); }); + it('refuses to add CLP with incorrect find', done => { + const levelPermissions = { + find: { '*': false }, + get: { '*': true }, + create: { '*': true }, + update: { '*': true }, + delete: { '*': true }, + addField: { '*': true }, + protectedFields: { '*': ['email'] }, + }; + config.database.loadSchema().then(schema => { + schema + .validateObject('NewClass', {}) + .then(() => schema.reloadData()) + .then(() => + schema.updateClass( + 'NewClass', + {}, + levelPermissions, + {}, + config.database + ) + ) + .then(done.fail) + .catch(error => { + expect(error.code).toEqual(Parse.Error.INVALID_JSON); + done(); + }); + }); + }); + + it('refuses to add CLP with incorrect protectedFields', done => { + const levelPermissions = { + find: { '*': true }, + get: { '*': true }, + create: { '*': true }, + update: { '*': true }, + delete: { '*': true }, + addField: { '*': true }, + protectedFields: { '*': 'email' }, + }; + config.database.loadSchema().then(schema => { + schema + .validateObject('NewClass', {}) + .then(() => schema.reloadData()) + .then(() => + schema.updateClass( + 'NewClass', + {}, + levelPermissions, + {}, + config.database + ) + ) + .then(done.fail) + .catch(error => { + expect(error.code).toEqual(Parse.Error.INVALID_JSON); + done(); + }); + }); + }); + it('will create classes', done => { config.database .loadSchema() @@ -706,6 +771,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); @@ -751,6 +817,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); @@ -782,6 +849,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); @@ -815,6 +883,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); @@ -1002,6 +1071,7 @@ describe('SchemaController', () => { update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }, }; expect(dd(actualSchema, expectedSchema)).toEqual(undefined); diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index 190f52d9..a9c9f84d 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -45,6 +45,9 @@ const defaultClassLevelPermissions = { delete: { '*': true, }, + protectedFields: { + '*': [], + }, }; const plainOldDataSchema = { @@ -1141,6 +1144,7 @@ describe('schemas', () => { update: {}, delete: {}, addField: {}, + protectedFields: {}, }); done(); }); @@ -2037,6 +2041,7 @@ describe('schemas', () => { update: {}, delete: {}, addField: {}, + protectedFields: {}, }); }) .then(done) diff --git a/src/Adapters/Storage/Mongo/MongoSchemaCollection.js b/src/Adapters/Storage/Mongo/MongoSchemaCollection.js index e2b2b2cb..160bccf4 100644 --- a/src/Adapters/Storage/Mongo/MongoSchemaCollection.js +++ b/src/Adapters/Storage/Mongo/MongoSchemaCollection.js @@ -62,6 +62,7 @@ const emptyCLPS = Object.freeze({ update: {}, delete: {}, addField: {}, + protectedFields: {}, }); const defaultCLPS = Object.freeze({ @@ -71,6 +72,7 @@ const defaultCLPS = Object.freeze({ update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }); function mongoSchemaToParseSchema(mongoSchema) { diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 94adf031..a424b5f2 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -106,6 +106,7 @@ const emptyCLPS = Object.freeze({ update: {}, delete: {}, addField: {}, + protectedFields: {}, }); const defaultCLPS = Object.freeze({ @@ -115,6 +116,7 @@ const defaultCLPS = Object.freeze({ update: { '*': true }, delete: { '*': true }, addField: { '*': true }, + protectedFields: { '*': [] }, }); const toParseSchema = schema => { diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 40e240ce..4e5ab437 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -203,6 +203,7 @@ const CLPValidKeys = Object.freeze([ 'addField', 'readUserFields', 'writeUserFields', + 'protectedFields', ]); function validateCLP(perms: ClassLevelPermissions, fields: SchemaFields) { if (!perms) { @@ -250,7 +251,10 @@ function validateCLP(perms: ClassLevelPermissions, fields: SchemaFields) { verifyPermissionKey(key); // @flow-disable-next const perm = perms[operation][key]; - if (perm !== true) { + if ( + perm !== true && + (operation !== 'protectedFields' || !Array.isArray(perm)) + ) { // @flow-disable-next throw new Parse.Error( Parse.Error.INVALID_JSON, diff --git a/src/RestQuery.js b/src/RestQuery.js index 44b16454..20a1b792 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -565,19 +565,8 @@ RestQuery.prototype.replaceDontSelect = function() { }); }; -const cleanResultOfSensitiveUserInfo = function(result, auth, config) { - delete result.password; - - if (auth.isMaster || (auth.user && auth.user.id === result.objectId)) { - return; - } - - for (const field of config.userSensitiveFields) { - delete result[field]; - } -}; - const cleanResultAuthData = function(result) { + delete result.password; if (result.authData) { Object.keys(result.authData).forEach(provider => { if (result.authData[provider] === null) { @@ -645,7 +634,6 @@ RestQuery.prototype.runFind = function(options = {}) { .then(results => { if (this.className === '_User') { for (var result of results) { - cleanResultOfSensitiveUserInfo(result, this.auth, this.config); cleanResultAuthData(result); } }