From 89e8868a856d5ee5c67632a0c342db4bc32e6079 Mon Sep 17 00:00:00 2001 From: Manuel Date: Wed, 21 Aug 2019 07:12:36 +0200 Subject: [PATCH] Get ParseConfig parameters with Master Key (#5954) * added saving, retrieving * added tests * fixed typo * added masterKeyOnly to schema controller --- spec/ParseGlobalConfig.spec.js | 57 +++++++++++++++++++++++++++-- src/Controllers/SchemaController.js | 1 + src/Routers/GlobalConfigRouter.js | 17 ++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/spec/ParseGlobalConfig.spec.js b/spec/ParseGlobalConfig.spec.js index ff5611ae..9f8b109e 100644 --- a/spec/ParseGlobalConfig.spec.js +++ b/spec/ParseGlobalConfig.spec.js @@ -20,10 +20,17 @@ describe('a GlobalConfig', () => { .upsertOneObject( '_GlobalConfig', { - fields: { objectId: { type: 'Number' }, params: { type: 'Object' } }, + fields: { + objectId: { type: 'Number' }, + params: { type: 'Object' }, + masterKeyOnly: { type: 'Object' }, + }, }, query, - { params: { companies: ['US', 'DK'] } } + { + params: { companies: ['US', 'DK'], internalParam: 'internal' }, + masterKeyOnly: { internalParam: true }, + } ) .then(done, err => { jfail(err); @@ -54,6 +61,44 @@ describe('a GlobalConfig', () => { }); }); + it('internal parameter can be retrieved with master key', done => { + request({ + url: 'http://localhost:8378/1/config', + json: true, + headers, + }).then(response => { + const body = response.data; + try { + expect(response.status).toEqual(200); + expect(body.params.internalParam).toEqual('internal'); + } catch (e) { + jfail(e); + } + done(); + }); + }); + + it('internal parameter cannot be retrieved without master key', done => { + request({ + url: 'http://localhost:8378/1/config', + json: true, + headers: { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + 'Content-Type': 'application/json', + }, + }).then(response => { + const body = response.data; + try { + expect(response.status).toEqual(200); + expect(body.params.internalParam).toBeUndefined(); + } catch (e) { + jfail(e); + } + done(); + }); + }); + it('can be updated when a master key exists', done => { request({ method: 'PUT', @@ -117,7 +162,13 @@ describe('a GlobalConfig', () => { method: 'PUT', url: 'http://localhost:8378/1/config', json: true, - body: { params: { companies: { __op: 'Delete' }, foo: 'bar' } }, + body: { + params: { + companies: { __op: 'Delete' }, + internalParam: { __op: 'Delete' }, + foo: 'bar', + }, + }, headers, }).then(response => { const body = response.data; diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index da75c2f1..61e01ef9 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -131,6 +131,7 @@ const defaultColumns: { [string]: SchemaFields } = Object.freeze({ _GlobalConfig: { objectId: { type: 'String' }, params: { type: 'Object' }, + masterKeyOnly: { type: 'Object' }, }, _GraphQLConfig: { objectId: { type: 'String' }, diff --git a/src/Routers/GlobalConfigRouter.js b/src/Routers/GlobalConfigRouter.js index 2b1d41bd..ca189ead 100644 --- a/src/Routers/GlobalConfigRouter.js +++ b/src/Routers/GlobalConfigRouter.js @@ -13,7 +13,20 @@ export class GlobalConfigRouter extends PromiseRouter { return { response: { params: {} } }; } const globalConfig = results[0]; - return { response: { params: globalConfig.params } }; + if (!req.auth.isMaster && globalConfig.masterKeyOnly !== undefined) { + for (const param in globalConfig.params) { + if (globalConfig.masterKeyOnly[param]) { + delete globalConfig.params[param]; + delete globalConfig.masterKeyOnly[param]; + } + } + } + return { + response: { + params: globalConfig.params, + masterKeyOnly: globalConfig.masterKeyOnly, + }, + }; }); } @@ -25,9 +38,11 @@ export class GlobalConfigRouter extends PromiseRouter { ); } const params = req.body.params; + const masterKeyOnly = req.body.masterKeyOnly || {}; // Transform in dot notation to make sure it works const update = Object.keys(params).reduce((acc, key) => { acc[`params.${key}`] = params[key]; + acc[`masterKeyOnly.${key}`] = masterKeyOnly[key] || false; return acc; }, {}); return req.config.database