From 51b49445d3cfe2b4775b7621471784aae9607d3f Mon Sep 17 00:00:00 2001 From: Yuri Komlev Date: Mon, 24 Feb 2020 20:17:46 +0300 Subject: [PATCH 1/2] consider default columns --- spec/ProtectedFields.spec.js | 48 +++++++++++++++++++++++++++-- src/Controllers/SchemaController.js | 5 ++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/spec/ProtectedFields.spec.js b/spec/ProtectedFields.spec.js index 3794996c6e..d5f193074f 100644 --- a/spec/ProtectedFields.spec.js +++ b/spec/ProtectedFields.spec.js @@ -777,7 +777,7 @@ describe('ProtectedFields', function() { object.set('revision', 0); object.set('test', 'test'); - await object.save({ useMasterKey: true }); + await object.save(null, { useMasterKey: true }); } beforeEach(async () => { @@ -812,6 +812,48 @@ describe('ProtectedFields', function() { }) ).toBeResolved(); }); + + it('should protect default fields (REST)', async () => { + await expectAsync( + updateCLP({ + get: { '*': true }, + protectedFields: { + '*': ['objectId', 'createdAt', 'updatedAt', 'ACL'], + }, + }) + ).toBeResolved(); + + const { data: result } = await request({ + url: `${Parse.serverURL}/classes/${className}/${object.id}`, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Rest-API-Key': 'rest', + 'Content-Type': 'application/json', + }, + }); + + expect(result.createdAt).toBe(undefined); + expect(result.updatedAt).toBe(undefined); + expect(result.ACL).toBe(undefined); + expect(result.objectId).toBe(undefined); + }); + + it('should allow protecting default fields (sdk)', async () => { + await updateCLP({ + get: { '*': true }, + protectedFields: { + '*': ['objectId', 'createdAt', 'updatedAt', 'ACL'], + }, + }); + + const q = new Parse.Query(className); + const result = await q.get(object.id); + + expect(result.id).toBe(undefined); + expect(result.getACL()).toBe(null); + expect(result.createdAt).toBe(undefined); + expect(result.updatedAt).toBe(undefined); + }); }); describe('targeting public access', () => { @@ -1310,10 +1352,10 @@ describe('ProtectedFields', function() { // admin supersets moder role moder.relation('roles').add(admin); - await moder.save({ useMasterKey: true }); + await moder.save(null, { useMasterKey: true }); tester.relation('roles').add(moder); - await tester.save({ useMasterKey: true }); + await tester.save(null, { useMasterKey: true }); const roleAdmin = `role:${admin.get('name')}`; const roleModer = `role:${moder.get('name')}`; diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 6948907744..39cf631858 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -308,7 +308,10 @@ function validateCLP( // if the field is in form of array for (const field of protectedFields) { // field should exist on collection - if (!Object.prototype.hasOwnProperty.call(fields, field)) { + if ( + !Object.prototype.hasOwnProperty.call(fields, field) && + !defaultColumns._Default[field] + ) { throw new Parse.Error( Parse.Error.INVALID_JSON, `Field '${field}' in protectedFields:${entity} does not exist` From 61c00dc5e5c658b4d0235b80d0c1d88342b2dc1a Mon Sep 17 00:00:00 2001 From: Yuri Komlev Date: Tue, 25 Feb 2020 19:18:37 +0300 Subject: [PATCH 2/2] disallow protecting default fields --- spec/ProtectedFields.spec.js | 56 +++++++++-------------------- src/Controllers/SchemaController.js | 12 ++++--- 2 files changed, 24 insertions(+), 44 deletions(-) diff --git a/spec/ProtectedFields.spec.js b/spec/ProtectedFields.spec.js index d5f193074f..fdc3c2d10a 100644 --- a/spec/ProtectedFields.spec.js +++ b/spec/ProtectedFields.spec.js @@ -813,46 +813,22 @@ describe('ProtectedFields', function() { ).toBeResolved(); }); - it('should protect default fields (REST)', async () => { - await expectAsync( - updateCLP({ - get: { '*': true }, - protectedFields: { - '*': ['objectId', 'createdAt', 'updatedAt', 'ACL'], - }, - }) - ).toBeResolved(); - - const { data: result } = await request({ - url: `${Parse.serverURL}/classes/${className}/${object.id}`, - headers: { - 'X-Parse-Application-Id': Parse.applicationId, - 'X-Parse-Rest-API-Key': 'rest', - 'Content-Type': 'application/json', - }, - }); - - expect(result.createdAt).toBe(undefined); - expect(result.updatedAt).toBe(undefined); - expect(result.ACL).toBe(undefined); - expect(result.objectId).toBe(undefined); - }); - - it('should allow protecting default fields (sdk)', async () => { - await updateCLP({ - get: { '*': true }, - protectedFields: { - '*': ['objectId', 'createdAt', 'updatedAt', 'ACL'], - }, - }); - - const q = new Parse.Query(className); - const result = await q.get(object.id); - - expect(result.id).toBe(undefined); - expect(result.getACL()).toBe(null); - expect(result.createdAt).toBe(undefined); - expect(result.updatedAt).toBe(undefined); + it('should not allow protecting default fields', async () => { + const defaultFields = ['objectId', 'createdAt', 'updatedAt', 'ACL']; + for (const field of defaultFields) { + await expectAsync( + updateCLP({ + protectedFields: { + '*': [field], + }, + }) + ).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_JSON, + `Default field '${field}' can not be protected` + ) + ); + } }); }); diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 39cf631858..435a4b5570 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -307,11 +307,15 @@ function validateCLP( // if the field is in form of array for (const field of protectedFields) { + // do not alloow to protect default fields + if (defaultColumns._Default[field]) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + `Default field '${field}' can not be protected` + ); + } // field should exist on collection - if ( - !Object.prototype.hasOwnProperty.call(fields, field) && - !defaultColumns._Default[field] - ) { + if (!Object.prototype.hasOwnProperty.call(fields, field)) { throw new Parse.Error( Parse.Error.INVALID_JSON, `Field '${field}' in protectedFields:${entity} does not exist`