From ca1ae336c99bef09026b36b17bcfcac0b7c25c69 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Wed, 19 Feb 2020 03:30:23 -0600 Subject: [PATCH 01/21] Websocket: unhandle rejection (#6418) * Websocket: unhandle rejection Closes: https://github.com/parse-community/parse-server/issues/6413, https://github.com/parse-community/parse-server/issues/6173 Prevent crashing on websocket error. Bonus points to anybody who can post a specific payload that the client sends that returns an error. * log the socket * fix tests * fix payload reference link --- spec/ParseLiveQuery.spec.js | 37 +++++++++++++++++++++++++++ spec/ParseWebSocketServer.spec.js | 13 +++++----- src/LiveQuery/ParseWebSocketServer.js | 4 +++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 74faa9aedc..fa83588b9d 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -24,6 +24,43 @@ describe('ParseLiveQuery', function() { await object.save(); }); + it('handle invalid websocket payload length', async done => { + await reconfigureServer({ + liveQuery: { + classNames: ['TestObject'], + }, + startLiveQueryServer: true, + verbose: false, + silent: true, + websocketTimeout: 100, + }); + const object = new TestObject(); + await object.save(); + + const query = new Parse.Query(TestObject); + query.equalTo('objectId', object.id); + const subscription = await query.subscribe(); + + // All control frames must have a payload length of 125 bytes or less. + // https://tools.ietf.org/html/rfc6455#section-5.5 + // + // 0x89 = 10001001 = ping + // 0xfe = 11111110 = first bit is masking the remaining 7 are 1111110 or 126 the payload length + // https://tools.ietf.org/html/rfc6455#section-5.2 + const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); + client.socket._socket.write(Buffer.from([0x89, 0xfe])); + + subscription.on('update', async object => { + expect(object.get('foo')).toBe('bar'); + done(); + }); + // Wait for Websocket timeout to reconnect + setTimeout(async () => { + object.set({ foo: 'bar' }); + await object.save(); + }, 1000); + }); + afterEach(async function(done) { const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); client.close(); diff --git a/spec/ParseWebSocketServer.spec.js b/spec/ParseWebSocketServer.spec.js index c9416f4c08..7bf8a5c57d 100644 --- a/spec/ParseWebSocketServer.spec.js +++ b/spec/ParseWebSocketServer.spec.js @@ -1,11 +1,12 @@ const { ParseWebSocketServer, } = require('../lib/LiveQuery/ParseWebSocketServer'); +const EventEmitter = require('events'); describe('ParseWebSocketServer', function() { beforeEach(function(done) { // Mock ws server - const EventEmitter = require('events'); + const mockServer = function() { return new EventEmitter(); }; @@ -22,11 +23,11 @@ describe('ParseWebSocketServer', function() { onConnectCallback, { websocketTimeout: 5 } ).server; - const ws = { - readyState: 0, - OPEN: 0, - ping: jasmine.createSpy('ping'), - }; + const ws = new EventEmitter(); + ws.readyState = 0; + ws.OPEN = 0; + ws.ping = jasmine.createSpy('ping'); + parseWebSocketServer.onConnection(ws); // Make sure callback is called diff --git a/src/LiveQuery/ParseWebSocketServer.js b/src/LiveQuery/ParseWebSocketServer.js index 9e0d18d2a1..606056fc2e 100644 --- a/src/LiveQuery/ParseWebSocketServer.js +++ b/src/LiveQuery/ParseWebSocketServer.js @@ -13,6 +13,10 @@ export class ParseWebSocketServer { logger.info('Parse LiveQuery Server starts running'); }; wss.onConnection = ws => { + ws.on('error', error => { + logger.error(error.message); + logger.error(JSON.stringify(ws)); + }); onConnect(new ParseWebSocket(ws)); // Send ping to client periodically const pingIntervalId = setInterval(() => { From 292bdb713a1557510b01986b1dd9d2d69efcf4ed Mon Sep 17 00:00:00 2001 From: Old Grandpa Date: Wed, 19 Feb 2020 12:34:08 +0300 Subject: [PATCH 02/21] Allow protectedFields for Authenticated users and Public. Fix userField with keys/excludedKeys (#6415) * fix error message and test it * protected fields fixes * clean * remove duplicate test, add some comments * no need for 'requiresAuthentication' --- spec/ParseGraphQLServer.spec.js | 80 +++ spec/ParseQuery.spec.js | 32 + spec/PointerPermissions.spec.js | 52 +- spec/ProtectedFields.spec.js | 961 +++++++++++++++++++++++++- spec/dev.js | 98 +++ spec/schemas.spec.js | 29 + src/Controllers/DatabaseController.js | 122 +++- src/Controllers/SchemaController.js | 55 +- src/Routers/ClassesRouter.js | 4 + 9 files changed, 1389 insertions(+), 44 deletions(-) create mode 100644 spec/dev.js diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index ca08f227db..cc44aaa8f5 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5,6 +5,8 @@ const fetch = require('node-fetch'); const FormData = require('form-data'); const ws = require('ws'); require('./helper'); +const { updateCLP } = require('./dev'); + const pluralize = require('pluralize'); const { getMainDefinition } = require('apollo-utilities'); const { ApolloLink, split } = require('apollo-link'); @@ -4632,6 +4634,84 @@ describe('ParseGraphQLServer', () => { ).toBeDefined(); }); + it('should respect protectedFields', async done => { + await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + + const className = 'GraphQLClass'; + + await updateCLP( + { + get: { '*': true }, + find: { '*': true }, + + protectedFields: { + '*': ['someField', 'someOtherField'], + authenticated: ['someField'], + 'userField:pointerToUser': [], + [user2.id]: [], + }, + }, + className + ); + + const getObject = async (className, id, user) => { + const headers = user + ? { ['X-Parse-Session-Token']: user.getSessionToken() } + : undefined; + + const specificQueryResult = await apolloClient.query({ + query: gql` + query GetSomeObject($id: ID!) { + get: graphQLClass(id: $id) { + pointerToUser { + username + id + } + someField + someOtherField + } + } + `, + variables: { + id: id, + }, + context: { + headers: headers, + }, + }); + + return specificQueryResult.data.get; + }; + + const id = object3.id; + + /* not authenticated */ + const objectPublic = await getObject(className, id, undefined); + + expect(objectPublic.someField).toBeNull(); + expect(objectPublic.someOtherField).toBeNull(); + + /* authenticated */ + const objectAuth = await getObject(className, id, user1); + + expect(objectAuth.someField).toBeNull(); + expect(objectAuth.someOtherField).toBe('B'); + + /* pointer field */ + const objectPointed = await getObject(className, id, user5); + + expect(objectPointed.someField).toBe('someValue3'); + expect(objectPointed.someOtherField).toBe('B'); + + /* for user id */ + const objectForUser = await getObject(className, id, user2); + + expect(objectForUser.someField).toBe('someValue3'); + expect(objectForUser.someOtherField).toBe('B'); + + done(); + }); describe_only_db('mongo')('read preferences', () => { it('should read from primary by default', async () => { try { diff --git a/spec/ParseQuery.spec.js b/spec/ParseQuery.spec.js index 260a48f217..ee4727404a 100644 --- a/spec/ParseQuery.spec.js +++ b/spec/ParseQuery.spec.js @@ -4868,4 +4868,36 @@ describe('Parse.Query testing', () => { const results = await query.find(); equal(results[0].get('array').length, 105); }); + + it('exclude keys (sdk query)', async done => { + const obj = new TestObject({ foo: 'baz', hello: 'world' }); + await obj.save(); + + const query = new Parse.Query('TestObject'); + query.exclude('foo'); + + const object = await query.get(obj.id); + expect(object.get('foo')).toBeUndefined(); + expect(object.get('hello')).toBe('world'); + done(); + }); + + xit('todo: exclude keys with select key (sdk query get)', async done => { + // there is some problem with js sdk caching + + const obj = new TestObject({ foo: 'baz', hello: 'world' }); + await obj.save(); + + const query = new Parse.Query('TestObject'); + + query.withJSON({ + keys: 'hello', + excludeKeys: 'hello', + }); + + const object = await query.get(obj.id); + expect(object.get('foo')).toBeUndefined(); + expect(object.get('hello')).toBeUndefined(); + done(); + }); }); diff --git a/spec/PointerPermissions.spec.js b/spec/PointerPermissions.spec.js index bd7e34b308..a3a1b9f498 100644 --- a/spec/PointerPermissions.spec.js +++ b/spec/PointerPermissions.spec.js @@ -2047,7 +2047,7 @@ describe('Pointer Permissions', () => { } async function logIn(userObject) { - await Parse.User.logIn(userObject.getUsername(), 'password'); + return await Parse.User.logIn(userObject.getUsername(), 'password'); } async function updateCLP(clp) { @@ -3098,5 +3098,55 @@ describe('Pointer Permissions', () => { done(); }); }); + + describe('using pointer-fields and queries with keys projection', () => { + let user1; + /** + * owner: user1 + * + * testers: [user1] + */ + let obj; + + /** + * Clear cache, create user and object, login user + */ + async function initialize() { + await Config.get(Parse.applicationId).database.schemaCache.clear(); + + user1 = await createUser('user1'); + user1 = await logIn(user1); + + obj = new Parse.Object(className); + + obj.set('owner', user1); + obj.set('field', 'field'); + obj.set('test', 'test'); + + await Parse.Object.saveAll([obj], { useMasterKey: true }); + + await obj.fetch(); + } + + beforeEach(async () => { + await initialize(); + }); + + it('should be enforced regardless of pointer-field being included in keys (select)', async done => { + await updateCLP({ + get: { '*': true }, + find: { pointerFields: ['owner'] }, + update: { pointerFields: ['owner'] }, + }); + + const query = new Parse.Query('AnObject'); + query.select('field', 'test'); + + const [object] = await query.find({ objectId: obj.id }); + expect(object.get('field')).toBe('field'); + expect(object.get('test')).toBe('test'); + done(); + }); + }); }); }); diff --git a/spec/ProtectedFields.spec.js b/spec/ProtectedFields.spec.js index 78e44f3bc1..3794996c6e 100644 --- a/spec/ProtectedFields.spec.js +++ b/spec/ProtectedFields.spec.js @@ -1,5 +1,13 @@ const Config = require('../lib/Config'); const Parse = require('parse/node'); +const request = require('../lib/request'); +const { + className, + createRole, + createUser, + logIn, + updateCLP, +} = require('./dev'); describe('ProtectedFields', function() { it('should handle and empty protectedFields', async function() { @@ -310,7 +318,7 @@ describe('ProtectedFields', function() { done(); }); - it('should create merge protected fields when using multiple pointer-permission fields', async done => { + it('should intersect protected fields when using multiple pointer-permission fields', async done => { const config = Config.get(Parse.applicationId); const obj = new Parse.Object('AnObject'); @@ -327,8 +335,8 @@ describe('ProtectedFields', function() { get: { '*': true }, find: { '*': true }, protectedFields: { - '*': [], - 'userField:owners': ['owners'], + '*': ['owners', 'owner', 'test'], + 'userField:owners': ['owners', 'owner'], 'userField:owner': ['owner'], }, } @@ -337,7 +345,7 @@ describe('ProtectedFields', function() { // Check if protectFields from pointer-permissions got combined await Parse.User.logIn('user1', 'password'); const objectAgain = await obj.fetch(); - expect(objectAgain.get('owners')).toBe(undefined); + expect(objectAgain.get('owners').length).toBe(1); expect(objectAgain.get('owner')).toBe(undefined); expect(objectAgain.get('test')).toBe('test'); done(); @@ -605,7 +613,7 @@ describe('ProtectedFields', function() { done(); }); - it('should create merge protected fields when using multiple pointer-permission fields', async done => { + it('should intersect protected fields when using multiple pointer-permission fields', async done => { const config = Config.get(Parse.applicationId); const obj = new Parse.Object('AnObject'); const obj2 = new Parse.Object('AnObject'); @@ -614,7 +622,6 @@ describe('ProtectedFields', function() { obj.set('owner', user1); obj.set('test', 'test'); obj2.set('owners', [user1]); - obj2.set('owner', user1); obj2.set('test', 'test2'); await Parse.Object.saveAll([obj, obj2]); @@ -626,8 +633,8 @@ describe('ProtectedFields', function() { get: { '*': true }, find: { '*': true }, protectedFields: { - '*': [], - 'userField:owners': ['owners'], + '*': ['owners', 'owner', 'test'], + 'userField:owners': ['owners', 'owner'], 'userField:owner': ['owner'], }, } @@ -642,7 +649,7 @@ describe('ProtectedFields', function() { results.sort((a, b) => a.get('test').localeCompare(b.get('test'))); expect(results.length).toBe(2); - expect(results[0].get('owners')).toBe(undefined); + expect(results[0].get('owners').length).toBe(1); expect(results[0].get('owner')).toBe(undefined); expect(results[0].get('test')).toBe('test'); expect(results[1].get('owners')).toBe(undefined); @@ -760,20 +767,24 @@ describe('ProtectedFields', function() { }); describe('schema setup', () => { - const className = 'AObject'; - async function updateCLP(clp) { - const config = Config.get(Parse.applicationId); - const schemaController = await config.database.loadSchema(); + let object; - await schemaController.updateClass(className, {}, clp); + async function initialize() { + await Config.get(Parse.applicationId).database.schemaCache.clear(); + + object = new Parse.Object(className); + + object.set('revision', 0); + object.set('test', 'test'); + + await object.save({ useMasterKey: true }); } - it('should fail setting non-existing protected field', async () => { - const object = new Parse.Object(className, { - revision: 0, - }); - await object.save(); + beforeEach(async () => { + await initialize(); + }); + it('should fail setting non-existing protected field', async done => { const field = 'non-existing'; const entity = '*'; @@ -789,6 +800,918 @@ describe('ProtectedFields', function() { `Field '${field}' in protectedFields:${entity} does not exist` ) ); + done(); + }); + + it('should allow setting authenticated', async () => { + await expectAsync( + updateCLP({ + protectedFields: { + authenticated: ['test'], + }, + }) + ).toBeResolved(); + }); + }); + + describe('targeting public access', () => { + let obj1; + + async function initialize() { + await Config.get(Parse.applicationId).database.schemaCache.clear(); + + obj1 = new Parse.Object(className); + + obj1.set('foo', 'foo'); + obj1.set('bar', 'bar'); + obj1.set('qux', 'qux'); + + await obj1.save(null, { + useMasterKey: true, + }); + } + + beforeEach(async () => { + await initialize(); + }); + + it('should hide field', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['foo'], + }, + }); + + // unauthenticated + const object = await obj1.fetch(); + + expect(object.get('foo')).toBe(undefined); + expect(object.get('bar')).toBeDefined(); + expect(object.get('qux')).toBeDefined(); + + done(); + }); + + it('should hide mutiple fields', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['foo', 'bar'], + }, + }); + + // unauthenticated + const object = await obj1.fetch(); + + expect(object.get('foo')).toBe(undefined); + expect(object.get('bar')).toBe(undefined); + expect(object.get('qux')).toBeDefined(); + + done(); + }); + + it('should not hide any fields when set as empty array', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': [], + }, + }); + + // unauthenticated + const object = await obj1.fetch(); + + expect(object.get('foo')).toBeDefined(); + expect(object.get('bar')).toBeDefined(); + expect(object.get('qux')).toBeDefined(); + expect(object.id).toBeDefined(); + expect(object.createdAt).toBeDefined(); + expect(object.updatedAt).toBeDefined(); + expect(object.getACL()).toBeDefined(); + + done(); + }); + }); + + describe('targeting authenticated', () => { + /** + * is **owner** of: _obj1_ + * + * is **tester** of: [ _obj1, obj2_ ] + */ + let user1; + + /** + * is **owner** of: _obj2_ + * + * is **tester** of: [ _obj1_ ] + */ + let user2; + + /** + * **owner**: _user1_ + * + * **testers**: [ _user1,user2_ ] + */ + let obj1; + + /** + * **owner**: _user2_ + * + * **testers**: [ _user1_ ] + */ + let obj2; + + async function initialize() { + await Config.get(Parse.applicationId).database.schemaCache.clear(); + + await Parse.User.logOut(); + + [user1, user2] = await Promise.all([ + createUser('user1'), + createUser('user2'), + ]); + + obj1 = new Parse.Object(className); + obj2 = new Parse.Object(className); + + obj1.set('owner', user1); + obj1.set('testers', [user1, user2]); + obj1.set('test', 'test'); + + obj2.set('owner', user2); + obj2.set('testers', [user1]); + obj2.set('test', 'test'); + + await Parse.Object.saveAll([obj1, obj2], { + useMasterKey: true, + }); + } + + beforeEach(async () => { + await initialize(); + }); + + it('should not hide any fields when set as empty array', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: [], + }, + }); + + // authenticated + await logIn(user1); + + const object = await obj1.fetch(); + + expect(object.get('owner')).toBeDefined(); + expect(object.get('testers')).toBeDefined(); + expect(object.get('test')).toBeDefined(); + expect(object.id).toBeDefined(); + expect(object.createdAt).toBeDefined(); + expect(object.updatedAt).toBeDefined(); + expect(object.getACL()).toBeDefined(); + + done(); + }); + + it('should hide fields for authenticated users only (* not set)', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: ['test'], + }, + }); + + // not authenticated + const objectNonAuth = await obj1.fetch(); + + expect(objectNonAuth.get('test')).toBeDefined(); + + // authenticated + await logIn(user1); + const object = await obj1.fetch(); + + expect(object.get('test')).toBe(undefined); + + done(); + }); + + it('should intersect public and auth for authenticated user', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['owner', 'testers'], + authenticated: ['testers'], + }, + }); + + // authenticated + await logIn(user1); + const objectAuth = await obj1.fetch(); + + // ( {A,B} intersect {B} ) == {B} + + expect(objectAuth.get('testers')).not.toBeDefined( + 'Should not be visible - protected for * and authenticated' + ); + expect(objectAuth.get('test')).toBeDefined( + 'Should be visible - not protected for everyone (* and authenticated)' + ); + expect(objectAuth.get('owner')).toBeDefined( + 'Should be visible - not protected for authenticated' + ); + + done(); + }); + + it('should have higher prio than public for logged in users (intersect)', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['test'], + authenticated: [], + }, + }); + // authenticated, permitted + await logIn(user1); + + const object = await obj1.fetch(); + expect(object.get('test')).toBe('test'); + + done(); + }); + + it('should have no effect on unauthenticated users (public not set)', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: ['test'], + }, + }); + + // unauthenticated, protected + const objectNonAuth = await obj1.fetch(); + expect(objectNonAuth.get('test')).toBe('test'); + + done(); + }); + + it('should protect multiple fields for authenticated users', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: ['test', 'owner'], + }, + }); + + // authenticated + await logIn(user1); + const object = await obj1.fetch(); + + expect(object.get('test')).toBe(undefined); + expect(object.get('owner')).toBe(undefined); + + done(); + }); + + it('should not be affected by rules not applicable to user (smoke)', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: ['owner', 'testers'], + [`role:${roleName}`]: ['test'], + 'userField:owner': [], + [user1.id]: [], + }, + }); + + // authenticated, non-owner, no role + await logIn(user2); + const objectNotOwned = await obj1.fetch(); + + expect(objectNotOwned.get('owner')).toBe(undefined); + expect(objectNotOwned.get('testers')).toBe(undefined); + expect(objectNotOwned.get('test')).toBeDefined(); + + done(); + }); + }); + + describe('targeting roles', () => { + let user1, user2; + + /** + * owner: user1 + * + * testers: [user1,user2] + */ + let obj1; + + /** + * owner: user2 + * + * testers: [user1] + */ + let obj2; + + async function initialize() { + await Config.get(Parse.applicationId).database.schemaCache.clear(); + + [user1, user2] = await Promise.all([ + createUser('user1'), + createUser('user2'), + ]); + + obj1 = new Parse.Object(className); + obj2 = new Parse.Object(className); + + obj1.set('owner', user1); + obj1.set('testers', [user1, user2]); + obj1.set('test', 'test'); + + obj2.set('owner', user2); + obj2.set('testers', [user1]); + obj2.set('test', 'test'); + + await Parse.Object.saveAll([obj1, obj2], { + useMasterKey: true, + }); + } + + beforeEach(async () => { + await initialize(); + }); + + it('should hide field when user belongs to a role', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + protectedFields: { + [`role:${roleName}`]: ['test'], + }, + get: { '*': true }, + find: { '*': true }, + }); + + // user has role + await logIn(user1); + + const object = await obj1.fetch(); + expect(object.get('test')).toBe(undefined); // field protected + expect(object.get('owner')).toBeDefined(); + expect(object.get('testers')).toBeDefined(); + + done(); + }); + + it('should not hide any fields when set as empty array', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + protectedFields: { + [`role:${roleName}`]: [], + }, + get: { '*': true }, + find: { '*': true }, + }); + + // user has role + await logIn(user1); + + const object = await obj1.fetch(); + + expect(object.get('owner')).toBeDefined(); + expect(object.get('testers')).toBeDefined(); + expect(object.get('test')).toBeDefined(); + expect(object.id).toBeDefined(); + expect(object.createdAt).toBeDefined(); + expect(object.updatedAt).toBeDefined(); + expect(object.getACL()).toBeDefined(); + + done(); + }); + + it('should hide multiple fields when user belongs to a role', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + [`role:${roleName}`]: ['test', 'owner'], + }, + }); + + // user has role + await logIn(user1); + + const object = await obj1.fetch(); + + expect(object.get('test')).toBe( + undefined, + 'Field should not be visible - protected by role' + ); + expect(object.get('owner')).toBe( + undefined, + 'Field should not be visible - protected by role' + ); + expect(object.get('testers')).toBeDefined(); + + done(); + }); + + it('should not protect when user does not belong to a role', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + [`role:${roleName}`]: ['test', 'owner'], + }, + }); + + // user doesn't have role + await logIn(user2); + const object = await obj1.fetch(); + + expect(object.get('test')).toBeDefined(); + expect(object.get('owner')).toBeDefined(); + expect(object.get('testers')).toBeDefined(); + + done(); + }); + + it('should intersect protected fields when user belongs to multiple roles', async done => { + const role1 = await createRole({ users: user1 }); + const role2 = await createRole({ users: user1 }); + + const role1name = role1.get('name'); + const role2name = role2.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + [`role:${role1name}`]: ['owner'], + [`role:${role2name}`]: ['test', 'owner'], + }, + }); + + // user has both roles + await logIn(user1); + const object = await obj1.fetch(); + + // "owner" is a result of intersection + expect(object.get('owner')).toBe( + undefined, + 'Must not be visible - protected for all roles the user belongs to' + ); + expect(object.get('test')).toBeDefined( + 'Has to be visible - is not protected for users with role1' + ); + done(); + }); + + it('should intersect protected fields when user belongs to multiple roles hierarchy', async done => { + const admin = await createRole({ + users: user1, + roleName: 'admin', + }); + + const moder = await createRole({ + users: [user1, user2], + roleName: 'moder', + }); + + const tester = await createRole({ + roleName: 'tester', + }); + + // admin supersets moder role + moder.relation('roles').add(admin); + await moder.save({ useMasterKey: true }); + + tester.relation('roles').add(moder); + await tester.save({ useMasterKey: true }); + + const roleAdmin = `role:${admin.get('name')}`; + const roleModer = `role:${moder.get('name')}`; + const roleTester = `role:${tester.get('name')}`; + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + [roleAdmin]: [], + [roleModer]: ['owner'], + [roleTester]: ['test', 'owner'], + }, + }); + + // user1 has admin & moder & tester roles, (moder includes tester). + await logIn(user1); + const object = await obj1.fetch(); + + // being admin makes all fields visible + expect(object.get('test')).toBeDefined( + 'Should be visible - admin role explicitly removes protection for all fields ( [] )' + ); + expect(object.get('owner')).toBeDefined( + 'Should be visible - admin role explicitly removes protection for all fields ( [] )' + ); + + // user2 has moder & tester role, moder includes tester. + await logIn(user2); + const objectAgain = await obj1.fetch(); + + // being moder allows "test" field + expect(objectAgain.get('owner')).toBe( + undefined, + '"owner" should not be visible - protected for each role user belongs to' + ); + expect(objectAgain.get('test')).toBeDefined( + 'Should be visible - moder role does not protect "test" field' + ); + + done(); + }); + + it('should be able to clear protected fields for role (protected for authenticated)', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: ['test'], + [`role:${roleName}`]: [], + }, + }); + + // user has role, test field visible + await logIn(user1); + const object = await obj1.fetch(); + expect(object.get('test')).toBe('test'); + + done(); + }); + + it('should determine protectedFields as intersection of field sets for public and role', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['test', 'owner'], + [`role:${roleName}`]: ['owner', 'testers'], + }, + }); + + // user has role + await logIn(user1); + + const object = await obj1.fetch(); + expect(object.get('test')).toBeDefined( + 'Should be visible - "test" is not protected for role user belongs to' + ); + expect(object.get('testers')).toBeDefined( + 'Should be visible - "testers" is allowed for everyone (*)' + ); + expect(object.get('owner')).toBe( + undefined, + 'Should not be visible - "test" is not allowed for both public(*) and role' + ); + done(); + }); + + it('should be determined as an intersection of protecedFields for authenticated and role', async done => { + const role = await createRole({ users: user1 }); + const roleName = role.get('name'); + + // this is an example of misunderstood configuration. + // If you allow (== do not restrict) some field for broader audience + // (having a role implies user inheres to 'authenticated' group) + // it's not possible to narrow by protecting field for a role. + // You'd have to protect it for 'authenticated' as well. + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + authenticated: ['test'], + [`role:${roleName}`]: ['owner'], + }, + }); + + // user has role + await logIn(user1); + const object = await obj1.fetch(); + + // + expect(object.get('test')).toBeDefined( + "Being both auhenticated and having a role leads to clearing protection on 'test' (by role rules)" + ); + expect(object.get('owner')).toBeDefined( + 'All authenticated users allowed to see "owner"' + ); + expect(object.get('testers')).toBeDefined(); + + done(); + }); + + it('should not hide fields when user does not belong to a role protectedFields set for', async done => { + const role = await createRole({ users: user2 }); + const roleName = role.get('name'); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + [`role:${roleName}`]: ['test'], + }, + }); + + // relate user1 to some role, no protectedFields for it + await createRole({ users: user1 }); + + await logIn(user1); + + const object = await obj1.fetch(); + expect(object.get('test')).toBeDefined( + 'Field should be visible - user belongs to a role that has no protectedFields set' + ); + + done(); + }); + }); + + describe('using pointer-fields and queries with keys projection', () => { + /* + * Pointer variant ("userField:column") relies on User ids + * returned after query executed (hides fields before sending it to client) + * If such column is excluded/not included (not returned from db because of 'project') + * there will be no user ids to check against + * and protectedFields won't be applied correctly. + */ + + let user1; + /** + * owner: user1 + * + * testers: [user1] + */ + let obj; + + let headers; + + /** + * Clear cache, create user and object, login user and setup rest headers with token + */ + async function initialize() { + await Config.get(Parse.applicationId).database.schemaCache.clear(); + + user1 = await createUser('user1'); + user1 = await logIn(user1); + + // await user1.fetch(); + obj = new Parse.Object(className); + + obj.set('owner', user1); + obj.set('field', 'field'); + obj.set('test', 'test'); + + await Parse.Object.saveAll([obj], { useMasterKey: true }); + + headers = { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Rest-API-Key': 'rest', + 'Content-Type': 'application/json', + 'X-Parse-Session-Token': user1.getSessionToken(), + }; + } + + beforeEach(async () => { + await initialize(); + }); + + it('should be enforced regardless of pointer-field being included in keys (select)', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['field', 'test'], + 'userField:owner': [], + }, + }); + + const query = new Parse.Query('AnObject'); + query.select('field', 'test'); + + const object = await query.get(obj.id); + expect(object.get('field')).toBe('field'); + expect(object.get('test')).toBe('test'); + done(); + }); + + it('should protect fields for query where pointer field is not included via keys (REST GET)', async done => { + const obj = new Parse.Object(className); + + obj.set('owner', user1); + obj.set('field', 'field'); + obj.set('test', 'test'); + + await Parse.Object.saveAll([obj], { useMasterKey: true }); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['field', 'test'], + 'userField:owner': ['test'], + }, + }); + + const { data: object } = await request({ + url: `${Parse.serverURL}/classes/${className}/${obj.id}`, + qs: { + keys: 'field,test', + }, + headers: headers, + }); + + expect(object.field).toBe( + 'field', + 'Should BE in response - not protected by "userField:owner"' + ); + expect(object.test).toBe( + undefined, + 'Should NOT be in response - protected by "userField:owner"' + ); + expect(object.owner).toBe( + undefined, + 'Should not be in response - not included in "keys"' + ); + done(); + }); + + it('should protect fields for query where pointer field is not included via keys (REST FIND)', async done => { + const obj = new Parse.Object(className); + + obj.set('owner', user1); + obj.set('field', 'field'); + obj.set('test', 'test'); + + await Parse.Object.saveAll([obj], { useMasterKey: true }); + + await obj.fetch(); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['field', 'test'], + 'userField:owner': ['test'], + }, + }); + + const { data } = await request({ + url: `${Parse.serverURL}/classes/${className}`, + qs: { + keys: 'field,test', + where: JSON.stringify({ objectId: obj.id }), + }, + headers, + }); + + const object = data.results[0]; + + expect(object.field).toBe( + 'field', + 'Should be in response - not protected by "userField:owner"' + ); + expect(object.test).toBe( + undefined, + 'Should not be in response - protected by "userField:owner"' + ); + expect(object.owner).toBe( + undefined, + 'Should not be in response - not included in "keys"' + ); + done(); + }); + + it('should protect fields for query where pointer field is in excludeKeys (REST GET)', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['field', 'test'], + 'userField:owner': ['test'], + }, + }); + + const { data: object } = await request({ + qs: { + excludeKeys: 'owner', + }, + headers, + url: `${Parse.serverURL}/classes/${className}/${obj.id}`, + }); + + expect(object.field).toBe( + 'field', + 'Should be in response - not protected by "userField:owner"' + ); + expect(object['test']).toBe( + undefined, + 'Should not be in response - protected by "userField:owner"' + ); + expect(object['owner']).toBe( + undefined, + 'Should not be in response - not included in "keys"' + ); + done(); + }); + + it('should protect fields for query where pointer field is in excludedKeys (REST FIND)', async done => { + await updateCLP({ + protectedFields: { + '*': ['field', 'test'], + 'userField:owner': ['test'], + }, + get: { '*': true }, + find: { '*': true }, + }); + + const { data } = await request({ + qs: { + excludeKeys: 'owner', + where: JSON.stringify({ objectId: obj.id }), + }, + headers, + url: `${Parse.serverURL}/classes/${className}`, + }); + + const object = data.results[0]; + + expect(object.field).toBe( + 'field', + 'Should be in response - not protected by "userField:owner"' + ); + expect(object.test).toBe( + undefined, + 'Should not be in response - protected by "userField:owner"' + ); + expect(object.owner).toBe( + undefined, + 'Should not be in response - not included in "keys"' + ); + done(); + }); + + xit('todo: should be enforced regardless of pointer-field being excluded', async done => { + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + protectedFields: { + '*': ['field', 'test'], + 'userField:owner': [], + }, + }); + + const query = new Parse.Query('AnObject'); + + /* TODO: this has some caching problems on JS-SDK (2.11.) side */ + // query.exclude('owner') + + const object = await query.get(obj.id); + expect(object.get('field')).toBe('field'); + expect(object.get('test')).toBe('test'); + expect(object.get('owner')).toBe(undefined); + done(); }); }); }); diff --git a/spec/dev.js b/spec/dev.js new file mode 100644 index 0000000000..31425dec40 --- /dev/null +++ b/spec/dev.js @@ -0,0 +1,98 @@ +const Config = require('../lib/Config'); +const Parse = require('parse/node'); + +const className = 'AnObject'; +const defaultRoleName = 'tester'; + +let schemaCache; + +module.exports = { + /* AnObject */ + className, + schemaCache, + + /** + * Creates and returns new user. + * + * This method helps to avoid 'User already exists' when re-running/debugging a single test. + * @param {string} username - username base, will be postfixed with current time in millis; + * @param {string} [password='password'] - optional, defaults to "password" if not set; + */ + createUser: async (username, password = 'password') => { + const user = new Parse.User({ + username: username + Date.now(), + password, + }); + await user.save(); + return user; + }, + + /** + * Logs the user in. + * + * If password not provided, default 'password' is used. + * @param {string} username - username base, will be postfixed with current time in millis; + * @param {string} [password='password'] - optional, defaults to "password" if not set; + */ + logIn: async (userObject, password) => { + return await Parse.User.logIn( + userObject.getUsername(), + password || 'password' + ); + }, + + /** + * Sets up Class-Level Permissions for 'AnObject' class. + * @param clp {ClassLevelPermissions} + */ + updateCLP: async (clp, targetClass = className) => { + const config = Config.get(Parse.applicationId); + const schemaController = await config.database.loadSchema(); + + await schemaController.updateClass(targetClass, {}, clp); + }, + + /** + * Creates and returns role. Adds user(s) if provided. + * + * This method helps to avoid errors when re-running/debugging a single test. + * + * @param {Parse.User|Parse.User[]} [users] - user or array of users to be related with this role; + * @param {string?} [roleName] - uses this name for role if provided. Generates from datetime if not set; + * @param {string?} [exactName] - sets exact name (no generated part added); + * @param {Parse.Role[]} [roles] - uses this name for role if provided. Generates from datetime if not set; + * @param {boolean} [read] - value for role's acl public read. Defaults to true; + * @param {boolean} [write] - value for role's acl public write. Defaults to true; + */ + createRole: async ({ + users = null, + exactName = defaultRoleName + Date.now(), + roleName = null, + roles = null, + read = true, + write = true, + }) => { + const acl = new Parse.ACL(); + acl.setPublicReadAccess(read); + acl.setPublicWriteAccess(write); + + const role = new Parse.Object('_Role'); + role.setACL(acl); + + // generate name based on roleName or use exactName (if botth not provided name is generated) + const name = roleName ? roleName + Date.now() : exactName; + role.set('name', name); + + if (roles) { + role.relation('roles').add(roles); + } + + if (users) { + role.relation('users').add(users); + } + + await role.save({ useMasterKey: true }); + + return role; + }, +}; diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index c547bf858a..661a19ee24 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -2861,6 +2861,35 @@ describe('schemas', () => { done(); }); + it('should be rejected if CLP pointerFields is not an array', async done => { + const config = Config.get(Parse.applicationId); + const schemaController = await config.database.loadSchema(); + + const operationKey = 'get'; + const entity = 'pointerFields'; + const value = {}; + + const schemaSetup = async () => + await schemaController.addClassIfNotExists( + 'AnObject', + {}, + { + [operationKey]: { + [entity]: value, + }, + } + ); + + await expectAsync(schemaSetup()).toBeRejectedWith( + new Parse.Error( + Parse.Error.INVALID_JSON, + `'${value}' is not a valid value for ${operationKey}[${entity}] - expected an array.` + ) + ); + + done(); + }); + describe('index management', () => { beforeEach(() => require('../lib/TestUtils').destroyAllDataPermanently()); it('cannot create index if field does not exist', done => { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 4b69d05e29..650781b5e5 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -217,7 +217,7 @@ const filterSensitiveData = ( return { key: key.substring(10), value: perms.protectedFields[key] }; }); - const newProtectedFields: Array = []; + const newProtectedFields: Array[] = []; let overrideProtectedFields = false; // check if the object grants the current user access based on the extracted fields @@ -238,12 +238,28 @@ const filterSensitiveData = ( if (pointerPermIncludesUser) { overrideProtectedFields = true; - newProtectedFields.push(...pointerPerm.value); + newProtectedFields.push(pointerPerm.value); } }); - // if atleast one pointer-permission affected the current user override the protectedFields - if (overrideProtectedFields) protectedFields = newProtectedFields; + // if at least one pointer-permission affected the current user + // intersect vs protectedFields from previous stage (@see addProtectedFields) + // Sets theory (intersections): A x (B x C) == (A x B) x C + if (overrideProtectedFields && protectedFields) { + newProtectedFields.push(protectedFields); + } + // intersect all sets of protectedFields + newProtectedFields.forEach(fields => { + if (fields) { + // if there're no protctedFields by other criteria ( id / role / auth) + // then we must intersect each set (per userField) + if (!protectedFields) { + protectedFields = fields; + } else { + protectedFields = protectedFields.filter(v => fields.includes(v)); + } + } + }); } } @@ -251,9 +267,16 @@ const filterSensitiveData = ( /* special treat for the user class: don't filter protectedFields if currently loggedin user is the retrieved user */ - if (!(isUserClass && userId && object.objectId === userId)) + if (!(isUserClass && userId && object.objectId === userId)) { protectedFields && protectedFields.forEach(k => delete object[k]); + // fields not requested by client (excluded), + //but were needed to apply protecttedFields + perms.protectedFields && + perms.protectedFields.temporaryKeys && + perms.protectedFields.temporaryKeys.forEach(k => delete object[k]); + } + if (!isUserClass) { return object; } @@ -1416,7 +1439,8 @@ class DatabaseController { className, query, aclGroup, - auth + auth, + queryOptions ); } if (!query) { @@ -1638,7 +1662,8 @@ class DatabaseController { className: string, query: any = {}, aclGroup: any[] = [], - auth: any = {} + auth: any = {}, + queryOptions: FullQueryOptions = {} ): null | string[] { const perms = schema.getClassLevelPermissions(className); if (!perms) return null; @@ -1648,14 +1673,85 @@ class DatabaseController { if (aclGroup.indexOf(query.objectId) > -1) return null; - // remove userField keys since they are filtered after querying - let protectedKeys = Object.keys(protectedFields).reduce((acc, val) => { - if (val.startsWith('userField:')) return acc; - return acc.concat(protectedFields[val]); + // for queries where "keys" are set and do not include all 'userField':{field}, + // we have to transparently include it, and then remove before returning to client + // Because if such key not projected the permission won't be enforced properly + // PS this is called when 'excludeKeys' already reduced to 'keys' + const preserveKeys = queryOptions.keys; + + // these are keys that need to be included only + // to be able to apply protectedFields by pointer + // and then unset before returning to client (later in filterSensitiveFields) + const serverOnlyKeys = []; + + const authenticated = auth.user; + + // map to allow check without array search + const roles = (auth.userRoles || []).reduce((acc, r) => { + acc[r] = protectedFields[r]; + return acc; + }, {}); + + // array of sets of protected fields. separate item for each applicable criteria + const protectedKeysSets = []; + + for (const key in protectedFields) { + // skip userFields + if (key.startsWith('userField:')) { + if (preserveKeys) { + const fieldName = key.substring(10); + if (!preserveKeys.includes(fieldName)) { + // 1. put it there temporarily + queryOptions.keys && queryOptions.keys.push(fieldName); + // 2. preserve it delete later + serverOnlyKeys.push(fieldName); + } + } + continue; + } + + // add public tier + if (key === '*') { + protectedKeysSets.push(protectedFields[key]); + continue; + } + + if (authenticated) { + if (key === 'authenticated') { + // for logged in users + protectedKeysSets.push(protectedFields[key]); + continue; + } + + if (roles[key] && key.startsWith('role:')) { + // add applicable roles + protectedKeysSets.push(roles[key]); + } + } + } + + // check if there's a rule for current user's id + if (authenticated) { + const userId = auth.user.id; + if (perms.protectedFields[userId]) { + protectedKeysSets.push(perms.protectedFields[userId]); + } + } + + // preserve fields to be removed before sending response to client + if (serverOnlyKeys.length > 0) { + perms.protectedFields.temporaryKeys = serverOnlyKeys; + } + + let protectedKeys = protectedKeysSets.reduce((acc, next) => { + if (next) { + acc.push(...next); + } + return acc; }, []); - [...(auth.userRoles || [])].forEach(role => { - const fields = protectedFields[role]; + // intersect all sets of protectedFields + protectedKeysSets.forEach(fields => { if (fields) { protectedKeys = protectedKeys.filter(v => fields.includes(v)); } diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 8c799d0533..6948907744 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -175,32 +175,62 @@ const volatileClasses = Object.freeze([ // Anything that start with role const roleRegex = /^role:.*/; -// Anything that starts with userField -const pointerPermissionRegex = /^userField:.*/; +// Anything that starts with userField (allowed for protected fields only) +const protectedFieldsPointerRegex = /^userField:.*/; // * permission const publicRegex = /^\*$/; -const requireAuthenticationRegex = /^requiresAuthentication$/; +const authenticatedRegex = /^authenticated$/; -const pointerFieldsRegex = /^pointerFields$/; +const requiresAuthenticationRegex = /^requiresAuthentication$/; -const permissionKeyRegex = Object.freeze([ +const clpPointerRegex = /^pointerFields$/; + +// regex for validating entities in protectedFields object +const protectedFieldsRegex = Object.freeze([ + protectedFieldsPointerRegex, + publicRegex, + authenticatedRegex, roleRegex, - pointerPermissionRegex, +]); + +// clp regex +const clpFieldsRegex = Object.freeze([ + clpPointerRegex, publicRegex, - requireAuthenticationRegex, - pointerFieldsRegex, + requiresAuthenticationRegex, + roleRegex, ]); function validatePermissionKey(key, userIdRegExp) { let matchesSome = false; - for (const regEx of permissionKeyRegex) { + for (const regEx of clpFieldsRegex) { + if (key.match(regEx) !== null) { + matchesSome = true; + break; + } + } + + // userId depends on startup options so it's dynamic + const valid = matchesSome || key.match(userIdRegExp) !== null; + if (!valid) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + `'${key}' is not a valid key for class level permissions` + ); + } +} + +function validateProtectedFieldsKey(key, userIdRegExp) { + let matchesSome = false; + for (const regEx of protectedFieldsRegex) { if (key.match(regEx) !== null) { matchesSome = true; break; } } + // userId regex depends on launch options so it's dynamic const valid = matchesSome || key.match(userIdRegExp) !== null; if (!valid) { throw new Parse.Error( @@ -264,7 +294,7 @@ function validateCLP( if (operationKey === 'protectedFields') { for (const entity in operation) { // throws on unexpected key - validatePermissionKey(entity, userIdRegExp); + validateProtectedFieldsKey(entity, userIdRegExp); const protectedFields = operation[entity]; @@ -301,6 +331,8 @@ function validateCLP( // throws on unexpected key validatePermissionKey(entity, userIdRegExp); + // entity can be either: + // "pointerFields": string[] if (entity === 'pointerFields') { const pointerFields = operation[entity]; @@ -311,13 +343,14 @@ function validateCLP( } else { throw new Parse.Error( Parse.Error.INVALID_JSON, - `'${pointerFields}' is not a valid value for protectedFields[${entity}] - expected an array.` + `'${pointerFields}' is not a valid value for ${operationKey}[${entity}] - expected an array.` ); } // proceed with next entity key continue; } + // or [entity]: boolean const permit = operation[entity]; if (permit !== true) { diff --git a/src/Routers/ClassesRouter.js b/src/Routers/ClassesRouter.js index 0cbc8d215d..d85101af6e 100644 --- a/src/Routers/ClassesRouter.js +++ b/src/Routers/ClassesRouter.js @@ -6,6 +6,7 @@ import Parse from 'parse/node'; const ALLOWED_GET_QUERY_KEYS = [ 'keys', 'include', + 'excludeKeys', 'readPreference', 'includeReadPreference', 'subqueryReadPreference', @@ -69,6 +70,9 @@ export class ClassesRouter extends PromiseRouter { if (body.include) { options.include = String(body.include); } + if (typeof body.excludeKeys == 'string') { + options.excludeKeys = body.excludeKeys; + } if (typeof body.readPreference === 'string') { options.readPreference = body.readPreference; } From 259d1193744499e3836ec8f15d054c50089d214c Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2020 22:17:45 +0000 Subject: [PATCH 03/21] =?UTF-8?q?Update=20pg-promise=20to=20the=20latest?= =?UTF-8?q?=20version=20=F0=9F=9A=80=20(#6434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(package): update pg-promise to version 10.4.4 * chore(package): update lockfile package-lock.json --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 957b5f97da..71c6e606b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10172,9 +10172,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pg": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.18.1.tgz", - "integrity": "sha512-1KtKBKg/zWrjEEv//klBbVOPGucuc7HHeJf6OEMueVcUeyF3yueHf+DvhVwBjIAe9/97RAydO/lWjkcMwssuEw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.18.2.tgz", + "integrity": "sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", @@ -10219,12 +10219,12 @@ "integrity": "sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg==" }, "pg-promise": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.4.3.tgz", - "integrity": "sha512-hdZTQ/NlqSlhKM9bMgDhKFiJX+hTuxUygEu1NBjGUtdTdenvnrxjaheeob6OEIxiYSmZFMG8uIsoVCIIPMgCsg==", + "version": "10.4.4", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.4.4.tgz", + "integrity": "sha512-N2NsOgKxrnNPwP0Q609ZmxmAZEo2TQ26SzSvlbZWQb8vteqUhOPpU/pHi9DGatJrPcXNoyr4xjRw42CNfEBg/w==", "requires": { "assert-options": "0.6.1", - "pg": "7.18.1", + "pg": "7.18.2", "pg-minify": "1.5.2", "spex": "3.0.1" } diff --git a/package.json b/package.json index 52004a063f..61203ff331 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "mongodb": "3.5.3", "node-rsa": "1.0.7", "parse": "2.11.0", - "pg-promise": "10.4.3", + "pg-promise": "10.4.4", "pluralize": "^8.0.0", "redis": "3.0.0", "semver": "7.1.3", From cbef90d66cd074c6b527304a0d9831e099657aa6 Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Fri, 21 Feb 2020 23:58:51 +0100 Subject: [PATCH 04/21] fix (#6431) --- src/GraphQL/transformers/mutation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GraphQL/transformers/mutation.js b/src/GraphQL/transformers/mutation.js index 6d5dbc601d..d2f3c8b7b5 100644 --- a/src/GraphQL/transformers/mutation.js +++ b/src/GraphQL/transformers/mutation.js @@ -122,7 +122,7 @@ const transformers = { parseGraphQLSchema, { config, auth, info } ) => { - if (Object.keys(value) === 0) + if (Object.keys(value).length === 0) throw new Parse.Error( Parse.Error.INVALID_POINTER, `You need to provide at least one operation on the relation mutation of field ${field}` @@ -203,7 +203,7 @@ const transformers = { parseGraphQLSchema, { config, auth, info } ) => { - if (Object.keys(value) > 1 || Object.keys(value) === 0) + if (Object.keys(value).length > 1 || Object.keys(value).length === 0) throw new Parse.Error( Parse.Error.INVALID_POINTER, `You need to provide link OR createLink on the pointer mutation of field ${field}` From d4690ca4255e62fdbb5c12019a8acb64fd4f2f55 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2020 23:10:07 +0000 Subject: [PATCH 05/21] =?UTF-8?q?Update=20bcrypt=20to=20the=20latest=20ver?= =?UTF-8?q?sion=20=F0=9F=9A=80=20(#6433)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update bcrypt to version 4.0.0 * chore(package): update lockfile package-lock.json --- package-lock.json | 20 +++++++++++++------- package.json | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 71c6e606b1..6c265cc17a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3457,12 +3457,12 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bcrypt": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.8.tgz", - "integrity": "sha512-jKV6RvLhI36TQnPDvUFqBEnGX9c8dRRygKxCZu7E+MgLfKZbmmXL8a7/SFFOyHoPNX9nV81cKRC5tbQfvEQtpw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-4.0.0.tgz", + "integrity": "sha512-UroxVJgmpeek3uxjY0IgtVtegM8EQqSLXnc5HE59m388MGZr0wPpRBqKJTaTraY3YEJOo1XIczExiEY9eeOCmg==", "optional": true, "requires": { - "nan": "2.14.0", + "node-addon-api": "^2.0.0", "node-pre-gyp": "0.14.0" } }, @@ -3870,9 +3870,9 @@ } }, "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "optional": true }, "ci-info": { @@ -9480,6 +9480,12 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-addon-api": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz", + "integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==", + "optional": true + }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", diff --git a/package.json b/package.json index 61203ff331..76643ed63d 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "parse-server": "./bin/parse-server" }, "optionalDependencies": { - "bcrypt": "3.0.8" + "bcrypt": "4.0.0" }, "collective": { "type": "opencollective", From c7f96c92cd152a6f88a9e57fa05a8c3120ad8854 Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Sat, 22 Feb 2020 00:12:49 +0100 Subject: [PATCH 06/21] GraphQL: Allow true GraphQL Schema Customization (#6360) * Allow real GraphQL Schema via ParseServer.start * wip * working * tests ok * add tests about enum/input use case * Add async function based merge * Better naming * remove useless condition --- spec/ParseGraphQLServer.spec.js | 374 +++++++++++++++------ src/GraphQL/ParseGraphQLSchema.js | 59 +++- src/GraphQL/helpers/objectsQueries.js | 21 +- src/GraphQL/loaders/defaultRelaySchema.js | 5 +- src/GraphQL/loaders/parseClassMutations.js | 48 ++- src/GraphQL/loaders/parseClassQueries.js | 11 +- src/GraphQL/loaders/parseClassTypes.js | 2 +- src/ParseServer.js | 4 +- 8 files changed, 397 insertions(+), 127 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index cc44aaa8f5..e9cbc64dc2 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -17,6 +17,14 @@ const { SubscriptionClient } = require('subscriptions-transport-ws'); const { WebSocketLink } = require('apollo-link-ws'); const ApolloClient = require('apollo-client').default; const gql = require('graphql-tag'); +const { + GraphQLObjectType, + GraphQLString, + GraphQLNonNull, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLSchema, +} = require('graphql'); const { ParseServer } = require('../'); const { ParseGraphQLServer } = require('../lib/GraphQL/ParseGraphQLServer'); const ReadPreference = require('mongodb').ReadPreference; @@ -10594,130 +10602,296 @@ describe('ParseGraphQLServer', () => { }); describe('Custom API', () => { - let httpServer; - const headers = { - 'X-Parse-Application-Id': 'test', - 'X-Parse-Javascript-Key': 'test', - }; - let apolloClient; - - beforeAll(async () => { - const expressApp = express(); - httpServer = http.createServer(expressApp); - parseGraphQLServer = new ParseGraphQLServer(parseServer, { - graphQLPath: '/graphql', - graphQLCustomTypeDefs: gql` - extend type Query { - hello: String @resolve - hello2: String @resolve(to: "hello") - userEcho(user: CreateUserFieldsInput!): User! @resolve - hello3: String! @mock(with: "Hello world!") - hello4: User! @mock(with: { username: "somefolk" }) - } - `, - }); - parseGraphQLServer.applyGraphQL(expressApp); - await new Promise(resolve => httpServer.listen({ port: 13377 }, resolve)); - const httpLink = createUploadLink({ - uri: 'http://localhost:13377/graphql', - fetch, - headers, - }); - apolloClient = new ApolloClient({ - link: httpLink, - cache: new InMemoryCache(), - defaultOptions: { - query: { - fetchPolicy: 'no-cache', + describe('GraphQL Schema Based', () => { + let httpServer; + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-Javascript-Key': 'test', + }; + let apolloClient; + beforeAll(async () => { + const expressApp = express(); + httpServer = http.createServer(expressApp); + parseGraphQLServer = new ParseGraphQLServer(parseServer, { + graphQLPath: '/graphql', + graphQLCustomTypeDefs: gql` + extend type Query { + hello: String @resolve + hello2: String @resolve(to: "hello") + userEcho(user: CreateUserFieldsInput!): User! @resolve + hello3: String! @mock(with: "Hello world!") + hello4: User! @mock(with: { username: "somefolk" }) + } + `, + }); + parseGraphQLServer.applyGraphQL(expressApp); + await new Promise(resolve => + httpServer.listen({ port: 13377 }, resolve) + ); + const httpLink = createUploadLink({ + uri: 'http://localhost:13377/graphql', + fetch, + headers, + }); + apolloClient = new ApolloClient({ + link: httpLink, + cache: new InMemoryCache(), + defaultOptions: { + query: { + fetchPolicy: 'no-cache', + }, }, - }, + }); }); - }); - afterAll(async () => { - await httpServer.close(); - }); - - it('can resolve a custom query using default function name', async () => { - Parse.Cloud.define('hello', async () => { - return 'Hello world!'; + afterAll(async () => { + await httpServer.close(); }); - const result = await apolloClient.query({ - query: gql` - query Hello { - hello - } - `, - }); + it('can resolve a custom query using default function name', async () => { + Parse.Cloud.define('hello', async () => { + return 'Hello world!'; + }); - expect(result.data.hello).toEqual('Hello world!'); - }); + const result = await apolloClient.query({ + query: gql` + query Hello { + hello + } + `, + }); - it('can resolve a custom query using function name set by "to" argument', async () => { - Parse.Cloud.define('hello', async () => { - return 'Hello world!'; + expect(result.data.hello).toEqual('Hello world!'); }); - const result = await apolloClient.query({ - query: gql` - query Hello { - hello2 - } - `, - }); + it('can resolve a custom query using function name set by "to" argument', async () => { + Parse.Cloud.define('hello', async () => { + return 'Hello world!'; + }); + + const result = await apolloClient.query({ + query: gql` + query Hello { + hello2 + } + `, + }); - expect(result.data.hello2).toEqual('Hello world!'); + expect(result.data.hello2).toEqual('Hello world!'); + }); }); - it('should resolve auto types', async () => { - Parse.Cloud.define('userEcho', async req => { - return req.params.user; + describe('SDL Based', () => { + let httpServer; + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-Javascript-Key': 'test', + }; + let apolloClient; + + beforeAll(async () => { + const expressApp = express(); + httpServer = http.createServer(expressApp); + const TypeEnum = new GraphQLEnumType({ + name: 'TypeEnum', + values: { + human: { value: 'human' }, + robot: { value: 'robot' }, + }, + }); + parseGraphQLServer = new ParseGraphQLServer(parseServer, { + graphQLPath: '/graphql', + graphQLCustomTypeDefs: new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + customQuery: { + type: new GraphQLNonNull(GraphQLString), + args: { + message: { type: new GraphQLNonNull(GraphQLString) }, + }, + resolve: (p, { message }) => message, + }, + }, + }), + types: [ + new GraphQLInputObjectType({ + name: 'CreateSomeClassFieldsInput', + fields: { + type: { type: TypeEnum }, + }, + }), + new GraphQLInputObjectType({ + name: 'UpdateSomeClassFieldsInput', + fields: { + type: { type: TypeEnum }, + }, + }), + new GraphQLObjectType({ + name: 'SomeClass', + fields: { + nameUpperCase: { + type: new GraphQLNonNull(GraphQLString), + resolve: p => p.name.toUpperCase(), + }, + type: { type: TypeEnum }, + language: { + type: new GraphQLEnumType({ + name: 'LanguageEnum', + values: { + fr: { value: 'fr' }, + en: { value: 'en' }, + }, + }), + resolve: () => 'fr', + }, + }, + }), + ], + }), + }); + + parseGraphQLServer.applyGraphQL(expressApp); + await new Promise(resolve => + httpServer.listen({ port: 13377 }, resolve) + ); + const httpLink = createUploadLink({ + uri: 'http://localhost:13377/graphql', + fetch, + headers, + }); + apolloClient = new ApolloClient({ + link: httpLink, + cache: new InMemoryCache(), + defaultOptions: { + query: { + fetchPolicy: 'no-cache', + }, + }, + }); + }); + + afterAll(async () => { + await httpServer.close(); }); - const result = await apolloClient.query({ - query: gql` - query UserEcho($user: CreateUserFieldsInput!) { - userEcho(user: $user) { - username + it('can resolve a custom query', async () => { + const result = await apolloClient.query({ + variables: { message: 'hello' }, + query: gql` + query CustomQuery($message: String!) { + customQuery(message: $message) } - } - `, - variables: { - user: { - username: 'somefolk', - password: 'somepassword', - }, - }, + `, + }); + expect(result.data.customQuery).toEqual('hello'); }); - expect(result.data.userEcho.username).toEqual('somefolk'); + it('can resolve a custom extend type', async () => { + const obj = new Parse.Object('SomeClass'); + await obj.save({ name: 'aname', type: 'robot' }); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const result = await apolloClient.query({ + variables: { id: obj.id }, + query: gql` + query someClass($id: ID!) { + someClass(id: $id) { + nameUpperCase + language + type + } + } + `, + }); + expect(result.data.someClass.nameUpperCase).toEqual('ANAME'); + expect(result.data.someClass.language).toEqual('fr'); + expect(result.data.someClass.type).toEqual('robot'); + + const result2 = await apolloClient.query({ + variables: { id: obj.id }, + query: gql` + query someClass($id: ID!) { + someClass(id: $id) { + name + language + } + } + `, + }); + expect(result2.data.someClass.name).toEqual('aname'); + expect(result.data.someClass.language).toEqual('fr'); + const result3 = await apolloClient.mutate({ + variables: { id: obj.id, name: 'anewname' }, + mutation: gql` + mutation someClass($id: ID!, $name: String!) { + updateSomeClass( + input: { id: $id, fields: { name: $name, type: human } } + ) { + someClass { + nameUpperCase + type + } + } + } + `, + }); + expect(result3.data.updateSomeClass.someClass.nameUpperCase).toEqual( + 'ANEWNAME' + ); + expect(result3.data.updateSomeClass.someClass.type).toEqual('human'); + }); }); + describe('Async Function Based Merge', () => { + let httpServer; + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-Javascript-Key': 'test', + }; + let apolloClient; - it('can mock a custom query with string', async () => { - const result = await apolloClient.query({ - query: gql` - query Hello { - hello3 - } - `, + beforeAll(async () => { + const expressApp = express(); + httpServer = http.createServer(expressApp); + parseGraphQLServer = new ParseGraphQLServer(parseServer, { + graphQLPath: '/graphql', + graphQLCustomTypeDefs: ({ autoSchema, mergeSchemas }) => + mergeSchemas({ schemas: [autoSchema] }), + }); + + parseGraphQLServer.applyGraphQL(expressApp); + await new Promise(resolve => + httpServer.listen({ port: 13377 }, resolve) + ); + const httpLink = createUploadLink({ + uri: 'http://localhost:13377/graphql', + fetch, + headers, + }); + apolloClient = new ApolloClient({ + link: httpLink, + cache: new InMemoryCache(), + defaultOptions: { + query: { + fetchPolicy: 'no-cache', + }, + }, + }); }); - expect(result.data.hello3).toEqual('Hello world!'); - }); + afterAll(async () => { + await httpServer.close(); + }); - it('can mock a custom query with auto type', async () => { - const result = await apolloClient.query({ - query: gql` - query Hello { - hello4 { - username + it('can resolve a query', async () => { + const result = await apolloClient.query({ + query: gql` + query Health { + health } - } - `, + `, + }); + expect(result.data.health).toEqual(true); }); - - expect(result.data.hello4.username).toEqual('somefolk'); }); }); }); diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index d01f5eee0a..d596eae5b7 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -197,19 +197,60 @@ class ParseGraphQLSchema { if (this.graphQLCustomTypeDefs) { schemaDirectives.load(this); - this.graphQLSchema = mergeSchemas({ - schemas: [ - this.graphQLSchemaDirectivesDefinitions, - this.graphQLAutoSchema, - this.graphQLCustomTypeDefs, - ], - mergeDirectives: true, - }); + if (typeof this.graphQLCustomTypeDefs.getTypeMap === 'function') { + const customGraphQLSchemaTypeMap = this.graphQLCustomTypeDefs.getTypeMap(); + Object.values(customGraphQLSchemaTypeMap).forEach( + customGraphQLSchemaType => { + if ( + !customGraphQLSchemaType || + !customGraphQLSchemaType.name || + customGraphQLSchemaType.name.startsWith('__') + ) { + return; + } + const autoGraphQLSchemaType = this.graphQLAutoSchema.getType( + customGraphQLSchemaType.name + ); + if (autoGraphQLSchemaType) { + autoGraphQLSchemaType._fields = { + ...autoGraphQLSchemaType._fields, + ...customGraphQLSchemaType._fields, + }; + } + } + ); + this.graphQLSchema = mergeSchemas({ + schemas: [ + this.graphQLSchemaDirectivesDefinitions, + this.graphQLCustomTypeDefs, + this.graphQLAutoSchema, + ], + mergeDirectives: true, + }); + } else if (typeof this.graphQLCustomTypeDefs === 'function') { + this.graphQLSchema = await this.graphQLCustomTypeDefs({ + directivesDefinitionsSchema: this.graphQLSchemaDirectivesDefinitions, + autoSchema: this.graphQLAutoSchema, + mergeSchemas, + }); + } else { + this.graphQLSchema = mergeSchemas({ + schemas: [ + this.graphQLSchemaDirectivesDefinitions, + this.graphQLAutoSchema, + this.graphQLCustomTypeDefs, + ], + mergeDirectives: true, + }); + } const graphQLSchemaTypeMap = this.graphQLSchema.getTypeMap(); Object.keys(graphQLSchemaTypeMap).forEach(graphQLSchemaTypeName => { const graphQLSchemaType = graphQLSchemaTypeMap[graphQLSchemaTypeName]; - if (typeof graphQLSchemaType.getFields === 'function') { + if ( + typeof graphQLSchemaType.getFields === 'function' && + this.graphQLCustomTypeDefs.definitions + ) { const graphQLCustomTypeDef = this.graphQLCustomTypeDefs.definitions.find( definition => definition.name.value === graphQLSchemaTypeName ); diff --git a/src/GraphQL/helpers/objectsQueries.js b/src/GraphQL/helpers/objectsQueries.js index 3e918c98b6..c1237deaea 100644 --- a/src/GraphQL/helpers/objectsQueries.js +++ b/src/GraphQL/helpers/objectsQueries.js @@ -3,6 +3,11 @@ import { offsetToCursor, cursorToOffset } from 'graphql-relay'; import rest from '../../rest'; import { transformQueryInputToParse } from '../transformers/query'; +const needToGetAllKeys = (fields, keys) => + keys + ? !!keys.split(',').find(keyName => !fields[keyName.split('.')[0]]) + : true; + const getObject = async ( className, objectId, @@ -12,10 +17,11 @@ const getObject = async ( includeReadPreference, config, auth, - info + info, + parseClass ) => { const options = {}; - if (keys) { + if (!needToGetAllKeys(parseClass.fields, keys)) { options.keys = keys; } if (include) { @@ -133,7 +139,14 @@ const findObjects = async ( // Silently replace the limit on the query with the max configured options.limit = config.maxLimit; } - if (keys) { + if ( + !needToGetAllKeys( + parseClasses.find( + ({ className: parseClassName }) => className === parseClassName + ).fields, + keys + ) + ) { options.keys = keys; } if (includeAll === true) { @@ -313,4 +326,4 @@ const calculateSkipAndLimit = ( }; }; -export { getObject, findObjects, calculateSkipAndLimit }; +export { getObject, findObjects, calculateSkipAndLimit, needToGetAllKeys }; diff --git a/src/GraphQL/loaders/defaultRelaySchema.js b/src/GraphQL/loaders/defaultRelaySchema.js index 3837bd5b9f..c3c2d9ccce 100644 --- a/src/GraphQL/loaders/defaultRelaySchema.js +++ b/src/GraphQL/loaders/defaultRelaySchema.js @@ -30,7 +30,10 @@ const load = parseGraphQLSchema => { undefined, config, auth, - info + info, + parseGraphQLSchema.parseClasses.find( + ({ className }) => type === className + ) )), }; } catch (e) { diff --git a/src/GraphQL/loaders/parseClassMutations.js b/src/GraphQL/loaders/parseClassMutations.js index 3ca333a0db..f41cccf5ed 100644 --- a/src/GraphQL/loaders/parseClassMutations.js +++ b/src/GraphQL/loaders/parseClassMutations.js @@ -112,8 +112,12 @@ const load = function( include, ['id', 'objectId', 'createdAt', 'updatedAt'] ); + const needToGetAllKeys = objectsQueries.needToGetAllKeys( + parseClass.fields, + keys + ); let optimizedObject = {}; - if (needGet) { + if (needGet && !needToGetAllKeys) { optimizedObject = await objectsQueries.getObject( className, createdObject.objectId, @@ -123,7 +127,21 @@ const load = function( undefined, config, auth, - info + info, + parseClass + ); + } else if (needToGetAllKeys) { + optimizedObject = await objectsQueries.getObject( + className, + createdObject.objectId, + undefined, + include, + undefined, + undefined, + config, + auth, + info, + parseClass ); } return { @@ -212,9 +230,12 @@ const load = function( include, ['id', 'objectId', 'updatedAt'] ); - + const needToGetAllKeys = objectsQueries.needToGetAllKeys( + parseClass.fields, + keys + ); let optimizedObject = {}; - if (needGet) { + if (needGet && !needToGetAllKeys) { optimizedObject = await objectsQueries.getObject( className, id, @@ -224,7 +245,21 @@ const load = function( undefined, config, auth, - info + info, + parseClass + ); + } else if (needToGetAllKeys) { + optimizedObject = await objectsQueries.getObject( + className, + id, + undefined, + include, + undefined, + undefined, + config, + auth, + info, + parseClass ); } return { @@ -301,7 +336,8 @@ const load = function( undefined, config, auth, - info + info, + parseClass ); } await objectsMutations.deleteObject( diff --git a/src/GraphQL/loaders/parseClassQueries.js b/src/GraphQL/loaders/parseClassQueries.js index 80667836d0..cd1e71d922 100644 --- a/src/GraphQL/loaders/parseClassQueries.js +++ b/src/GraphQL/loaders/parseClassQueries.js @@ -14,7 +14,7 @@ const getParseClassQueryConfig = function( return (parseClassConfig && parseClassConfig.query) || {}; }; -const getQuery = async (className, _source, args, context, queryInfo) => { +const getQuery = async (parseClass, _source, args, context, queryInfo) => { let { id } = args; const { options } = args; const { readPreference, includeReadPreference } = options || {}; @@ -23,14 +23,14 @@ const getQuery = async (className, _source, args, context, queryInfo) => { const globalIdObject = fromGlobalId(id); - if (globalIdObject.type === className) { + if (globalIdObject.type === parseClass.className) { id = globalIdObject.id; } const { keys, include } = extractKeysAndInclude(selectedFields); return await objectsQueries.getObject( - className, + parseClass.className, id, keys, include, @@ -38,7 +38,8 @@ const getQuery = async (className, _source, args, context, queryInfo) => { includeReadPreference, config, auth, - info + info, + parseClass ); }; @@ -79,7 +80,7 @@ const load = function( ), async resolve(_source, args, context, queryInfo) { try { - return await getQuery(className, _source, args, context, queryInfo); + return await getQuery(parseClass, _source, args, context, queryInfo); } catch (e) { parseGraphQLSchema.handleError(e); } diff --git a/src/GraphQL/loaders/parseClassTypes.js b/src/GraphQL/loaders/parseClassTypes.js index 4909c3e992..b0272c4de6 100644 --- a/src/GraphQL/loaders/parseClassTypes.js +++ b/src/GraphQL/loaders/parseClassTypes.js @@ -436,7 +436,7 @@ const load = ( ); const parseOrder = order && order.join(','); - return await objectsQueries.findObjects( + return objectsQueries.findObjects( source[field].className, { $relatedTo: { diff --git a/src/ParseServer.js b/src/ParseServer.js index 5611c50491..1fd279b4c7 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -262,10 +262,12 @@ class ParseServer { if (options.mountGraphQL === true || options.mountPlayground === true) { let graphQLCustomTypeDefs = undefined; - if (options.graphQLSchema) { + if (typeof options.graphQLSchema === 'string') { graphQLCustomTypeDefs = parse( fs.readFileSync(options.graphQLSchema, 'utf8') ); + } else if (typeof options.graphQLSchema === 'object') { + graphQLCustomTypeDefs = options.graphQLSchema; } const parseGraphQLServer = new ParseGraphQLServer(this, { From 9d7da58129994cd91b427c5ce5ae650c8060e3d4 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2020 03:52:39 +0000 Subject: [PATCH 07/21] =?UTF-8?q?Update=20flow-bin=20to=20the=20latest=20v?= =?UTF-8?q?ersion=20=F0=9F=9A=80=20(#6438)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update flow-bin to version 0.119.0 * chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c265cc17a..f2d3f0366d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5885,9 +5885,9 @@ "dev": true }, "flow-bin": { - "version": "0.118.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.118.0.tgz", - "integrity": "sha512-jlbUu0XkbpXeXhan5xyTqVK1jmEKNxE8hpzznI3TThHTr76GiFwK0iRzhDo4KNy+S9h/KxHaqVhTP86vA6wHCg==", + "version": "0.119.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.119.0.tgz", + "integrity": "sha512-fCVv++rjBsx/q6YVeB3F+A/owztjUO5PyBLwhGZdK5igVmiFQ8RKBTR9T2mb+SQRLZJJhl/xwPLhNzr3dBba6w==", "dev": true }, "follow-redirects": { diff --git a/package.json b/package.json index 76643ed63d..f6bb772dfa 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "deep-diff": "1.0.2", "eslint": "6.8.0", "eslint-plugin-flowtype": "4.5.0", - "flow-bin": "0.118.0", + "flow-bin": "0.119.0", "form-data": "3.0.0", "gaze": "1.1.3", "graphql-tag": "^2.10.1", From 5c7918980cf9b3bccd5b521e1831fa6b65d32705 Mon Sep 17 00:00:00 2001 From: Arthur Cinader <700572+acinader@users.noreply.github.com> Date: Thu, 27 Feb 2020 10:56:14 -0800 Subject: [PATCH 08/21] Set min mongodb to 3.6 in prep for parse-server 4.0 (#6445) * Set min mongodb to 3.6 in prep for parse-server 4.0 fixes: 6444 * don't use anonymous functions when we can just pass the function. Also remove the boolean argument in tests that no longer exists. * generate the correct lock file. ooops. --- README.md | 6 +- package-lock.json | 6 +- package.json | 2 +- spec/DatabaseController.spec.js | 148 ++++++++------------------ src/Config.js | 3 +- src/Controllers/DatabaseController.js | 87 ++------------- src/Controllers/index.js | 4 +- src/Options/Definitions.js | 6 -- src/Options/docs.js | 1 - src/Options/index.js | 4 - 10 files changed, 60 insertions(+), 207 deletions(-) diff --git a/README.md b/README.md index e73f9b9044..b935b83e03 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,6 @@

- MongoDB 3.2 - MongoDB 3.4 MongoDB 3.6 MongoDB 4.0

@@ -80,7 +78,7 @@ The fastest and easiest way to get started is to run MongoDB and Parse Server lo Before you start make sure you have installed: -- [NodeJS](https://www.npmjs.com/) that includes `npm` +- [NodeJS](https://www.npmjs.com/) that includes `npm` - [MongoDB](https://www.mongodb.com/) or [PostgreSQL](https://www.postgresql.org/) - Optionally [Docker](https://www.docker.com/) @@ -337,7 +335,7 @@ It’s possible to change the default pages of the app and redirect the user to ```js var server = ParseServer({ ...otherOptions, - + customPages: { passwordResetSuccess: "http://yourapp.com/passwordResetSuccess", verifyEmailSuccess: "http://yourapp.com/verifyEmailSuccess", diff --git a/package-lock.json b/package-lock.json index f2d3f0366d..03b47a94db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9032,9 +9032,9 @@ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "mongodb": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.3.tgz", - "integrity": "sha512-II7P7A3XUdPiXRgcN96qIoRa1oesM6qLNZkzfPluNZjVkgQk3jnQwOT6/uDk4USRDTTLjNFw2vwfmbRGTA7msg==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.4.tgz", + "integrity": "sha512-xGH41Ig4dkSH5ROGezkgDbsgt/v5zbNUwE3TcFsSbDc6Qn3Qil17dhLsESSDDPTiyFDCPJRpfd4887dtsPgKtA==", "requires": { "bl": "^2.2.0", "bson": "^1.1.1", diff --git a/package.json b/package.json index f6bb772dfa..d84b71e896 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "lodash": "4.17.15", "lru-cache": "5.1.1", "mime": "2.4.4", - "mongodb": "3.5.3", + "mongodb": "3.5.4", "node-rsa": "1.0.7", "parse": "2.11.0", "pg-promise": "10.4.4", diff --git a/spec/DatabaseController.spec.js b/spec/DatabaseController.spec.js index 70b554f83a..af373e64f2 100644 --- a/spec/DatabaseController.spec.js +++ b/spec/DatabaseController.spec.js @@ -3,118 +3,56 @@ const validateQuery = DatabaseController._validateQuery; describe('DatabaseController', function() { describe('validateQuery', function() { - describe('with skipMongoDBServer13732Workaround disabled (the default)', function() { - it('should restructure simple cases of SERVER-13732', done => { - const query = { - $or: [{ a: 1 }, { a: 2 }], - _rperm: { $in: ['a', 'b'] }, - foo: 3, - }; - validateQuery(query, false); - expect(query).toEqual({ - $or: [ - { a: 1, _rperm: { $in: ['a', 'b'] }, foo: 3 }, - { a: 2, _rperm: { $in: ['a', 'b'] }, foo: 3 }, - ], - }); - done(); - }); - - it('should not restructure SERVER-13732 queries with $nears', done => { - let query = { $or: [{ a: 1 }, { b: 1 }], c: { $nearSphere: {} } }; - validateQuery(query, false); - expect(query).toEqual({ - $or: [{ a: 1 }, { b: 1 }], - c: { $nearSphere: {} }, - }); - query = { $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } }; - validateQuery(query, false); - expect(query).toEqual({ $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } }); - done(); - }); - - it('should push refactored keys down a tree for SERVER-13732', done => { - const query = { - a: 1, - $or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }], - }; - validateQuery(query, false); - expect(query).toEqual({ - $or: [ - { $or: [{ b: 1, a: 1 }, { b: 2, a: 1 }] }, - { $or: [{ c: 1, a: 1 }, { c: 2, a: 1 }] }, - ], - }); - done(); - }); - - it('should reject invalid queries', done => { - expect(() => validateQuery({ $or: { a: 1 } }, false)).toThrow(); - done(); - }); - - it('should accept valid queries', done => { - expect(() => - validateQuery({ $or: [{ a: 1 }, { b: 2 }] }, false) - ).not.toThrow(); - done(); - }); + it('should not restructure simple cases of SERVER-13732', done => { + const query = { + $or: [{ a: 1 }, { a: 2 }], + _rperm: { $in: ['a', 'b'] }, + foo: 3, + }; + validateQuery(query); + expect(query).toEqual({ + $or: [{ a: 1 }, { a: 2 }], + _rperm: { $in: ['a', 'b'] }, + foo: 3, + }); + done(); }); - describe('with skipMongoDBServer13732Workaround enabled', function() { - it('should not restructure simple cases of SERVER-13732', done => { - const query = { - $or: [{ a: 1 }, { a: 2 }], - _rperm: { $in: ['a', 'b'] }, - foo: 3, - }; - validateQuery(query, true); - expect(query).toEqual({ - $or: [{ a: 1 }, { a: 2 }], - _rperm: { $in: ['a', 'b'] }, - foo: 3, - }); - done(); - }); + it('should not restructure SERVER-13732 queries with $nears', done => { + let query = { $or: [{ a: 1 }, { b: 1 }], c: { $nearSphere: {} } }; + validateQuery(query); + expect(query).toEqual({ + $or: [{ a: 1 }, { b: 1 }], + c: { $nearSphere: {} }, + }); + query = { $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } }; + validateQuery(query); + expect(query).toEqual({ $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } }); + done(); + }); - it('should not restructure SERVER-13732 queries with $nears', done => { - let query = { $or: [{ a: 1 }, { b: 1 }], c: { $nearSphere: {} } }; - validateQuery(query, true); - expect(query).toEqual({ - $or: [{ a: 1 }, { b: 1 }], - c: { $nearSphere: {} }, - }); - query = { $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } }; - validateQuery(query, true); - expect(query).toEqual({ $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } }); - done(); + it('should not push refactored keys down a tree for SERVER-13732', done => { + const query = { + a: 1, + $or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }], + }; + validateQuery(query); + expect(query).toEqual({ + a: 1, + $or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }], }); - it('should not push refactored keys down a tree for SERVER-13732', done => { - const query = { - a: 1, - $or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }], - }; - validateQuery(query, true); - expect(query).toEqual({ - a: 1, - $or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }], - }); - - done(); - }); + done(); + }); - it('should reject invalid queries', done => { - expect(() => validateQuery({ $or: { a: 1 } }, true)).toThrow(); - done(); - }); + it('should reject invalid queries', done => { + expect(() => validateQuery({ $or: { a: 1 } })).toThrow(); + done(); + }); - it('should accept valid queries', done => { - expect(() => - validateQuery({ $or: [{ a: 1 }, { b: 2 }] }, true) - ).not.toThrow(); - done(); - }); + it('should accept valid queries', done => { + expect(() => validateQuery({ $or: [{ a: 1 }, { b: 2 }] })).not.toThrow(); + done(); }); }); }); diff --git a/src/Config.js b/src/Config.js index 8d31d3d9ea..2077626ff8 100644 --- a/src/Config.js +++ b/src/Config.js @@ -34,8 +34,7 @@ export class Config { ); config.database = new DatabaseController( cacheInfo.databaseController.adapter, - schemaCache, - cacheInfo.skipMongoDBServer13732Workaround + schemaCache ); } else { config[key] = cacheInfo[key]; diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 650781b5e5..5c3b8ab342 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -69,73 +69,14 @@ const isSpecialQueryKey = key => { return specialQuerykeys.indexOf(key) >= 0; }; -const validateQuery = ( - query: any, - skipMongoDBServer13732Workaround: boolean -): void => { +const validateQuery = (query: any): void => { if (query.ACL) { throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.'); } if (query.$or) { if (query.$or instanceof Array) { - query.$or.forEach(el => - validateQuery(el, skipMongoDBServer13732Workaround) - ); - - if (!skipMongoDBServer13732Workaround) { - /* In MongoDB 3.2 & 3.4, $or queries which are not alone at the top - * level of the query can not make efficient use of indexes due to a - * long standing bug known as SERVER-13732. - * - * This bug was fixed in MongoDB version 3.6. - * - * For versions pre-3.6, the below logic produces a substantial - * performance improvement inside the database by avoiding the bug. - * - * For versions 3.6 and above, there is no performance improvement and - * the logic is unnecessary. Some query patterns are even slowed by - * the below logic, due to the bug having been fixed and better - * query plans being chosen. - * - * When versions before 3.4 are no longer supported by this project, - * this logic, and the accompanying `skipMongoDBServer13732Workaround` - * flag, can be removed. - * - * This block restructures queries in which $or is not the sole top - * level element by moving all other top-level predicates inside every - * subdocument of the $or predicate, allowing MongoDB's query planner - * to make full use of the most relevant indexes. - * - * EG: {$or: [{a: 1}, {a: 2}], b: 2} - * Becomes: {$or: [{a: 1, b: 2}, {a: 2, b: 2}]} - * - * The only exceptions are $near and $nearSphere operators, which are - * constrained to only 1 operator per query. As a result, these ops - * remain at the top level - * - * https://jira.mongodb.org/browse/SERVER-13732 - * https://github.com/parse-community/parse-server/issues/3767 - */ - Object.keys(query).forEach(key => { - const noCollisions = !query.$or.some(subq => - Object.prototype.hasOwnProperty.call(subq, key) - ); - let hasNears = false; - if (query[key] != null && typeof query[key] == 'object') { - hasNears = '$near' in query[key] || '$nearSphere' in query[key]; - } - if (key != '$or' && noCollisions && !hasNears) { - query.$or.forEach(subquery => { - subquery[key] = query[key]; - }); - delete query[key]; - } - }); - query.$or.forEach(el => - validateQuery(el, skipMongoDBServer13732Workaround) - ); - } + query.$or.forEach(validateQuery); } else { throw new Parse.Error( Parse.Error.INVALID_QUERY, @@ -146,9 +87,7 @@ const validateQuery = ( if (query.$and) { if (query.$and instanceof Array) { - query.$and.forEach(el => - validateQuery(el, skipMongoDBServer13732Workaround) - ); + query.$and.forEach(validateQuery); } else { throw new Parse.Error( Parse.Error.INVALID_QUERY, @@ -159,9 +98,7 @@ const validateQuery = ( if (query.$nor) { if (query.$nor instanceof Array && query.$nor.length > 0) { - query.$nor.forEach(el => - validateQuery(el, skipMongoDBServer13732Workaround) - ); + query.$nor.forEach(validateQuery); } else { throw new Parse.Error( Parse.Error.INVALID_QUERY, @@ -487,21 +424,15 @@ class DatabaseController { adapter: StorageAdapter; schemaCache: any; schemaPromise: ?Promise; - skipMongoDBServer13732Workaround: boolean; _transactionalSession: ?any; - constructor( - adapter: StorageAdapter, - schemaCache: any, - skipMongoDBServer13732Workaround: boolean - ) { + constructor(adapter: StorageAdapter, schemaCache: any) { this.adapter = adapter; this.schemaCache = schemaCache; // We don't want a mutable this.schema, because then you could have // one request that uses different schemas for different parts of // it. Instead, use loadSchema to get a schema. this.schemaPromise = null; - this.skipMongoDBServer13732Workaround = skipMongoDBServer13732Workaround; this._transactionalSession = null; } @@ -660,7 +591,7 @@ class DatabaseController { if (acl) { query = addWriteACL(query, acl); } - validateQuery(query, this.skipMongoDBServer13732Workaround); + validateQuery(query); return schemaController .getOneSchema(className, true) .catch(error => { @@ -939,7 +870,7 @@ class DatabaseController { if (acl) { query = addWriteACL(query, acl); } - validateQuery(query, this.skipMongoDBServer13732Workaround); + validateQuery(query); return schemaController .getOneSchema(className) .catch(error => { @@ -1460,7 +1391,7 @@ class DatabaseController { query = addReadACL(query, aclGroup); } } - validateQuery(query, this.skipMongoDBServer13732Workaround); + validateQuery(query); if (count) { if (!classExists) { return 0; @@ -1893,7 +1824,7 @@ class DatabaseController { ]); } - static _validateQuery: (any, boolean) => void; + static _validateQuery: any => void; } module.exports = DatabaseController; diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 8ef767933f..d10ad8001c 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -171,7 +171,6 @@ export function getDatabaseController( const { databaseURI, databaseOptions, - skipMongoDBServer13732Workaround, collectionPrefix, schemaCacheTTL, enableSingleSchemaCache, @@ -195,8 +194,7 @@ export function getDatabaseController( } return new DatabaseController( databaseAdapter, - new SchemaCache(cacheController, schemaCacheTTL, enableSingleSchemaCache), - skipMongoDBServer13732Workaround + new SchemaCache(cacheController, schemaCacheTTL, enableSingleSchemaCache) ); } diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 4bded75ab9..725002034c 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -371,12 +371,6 @@ module.exports.ParseServerOptions = { help: 'Disables console output', action: parsers.booleanParser, }, - skipMongoDBServer13732Workaround: { - env: 'PARSE_SKIP_MONGODB_SERVER_13732_WORKAROUND', - help: 'Circumvent Parse workaround for historical MongoDB bug SERVER-13732', - action: parsers.booleanParser, - default: false, - }, startLiveQueryServer: { env: 'PARSE_SERVER_START_LIVE_QUERY_SERVER', help: 'Starts the liveQuery server', diff --git a/src/Options/docs.js b/src/Options/docs.js index 098fefb563..9e5b6ac8f8 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -67,7 +67,6 @@ * @property {String} serverURL URL to your parse server with http:// or https://. * @property {Number} sessionLength Session duration, in seconds, defaults to 1 year * @property {Boolean} silent Disables console output - * @property {Boolean} skipMongoDBServer13732Workaround Circumvent Parse workaround for historical MongoDB bug SERVER-13732 * @property {Boolean} startLiveQueryServer Starts the liveQuery server * @property {String[]} userSensitiveFields Personally identifiable information fields in the user table the should be removed for non-authorized users. Deprecated @see protectedFields * @property {Boolean} verbose Set the logging to verbose diff --git a/src/Options/index.js b/src/Options/index.js index 43922ed36c..3aa5b7fc6b 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -64,10 +64,6 @@ export interface ParseServerOptions { databaseOptions: ?any; /* Adapter module for the database */ databaseAdapter: ?Adapter; - /* Circumvent Parse workaround for historical MongoDB bug SERVER-13732 - :ENV: PARSE_SKIP_MONGODB_SERVER_13732_WORKAROUND - :DEFAULT: false */ - skipMongoDBServer13732Workaround: ?boolean; /* Full path to your cloud code main.js */ cloud: ?string; /* A collection prefix for the classes From 8487d2376f1327b60059ce72450cb401f3508fc2 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2020 22:30:12 +0000 Subject: [PATCH 09/21] =?UTF-8?q?Update=20babel-eslint=20to=20the=20latest?= =?UTF-8?q?=20version=20=F0=9F=9A=80=20(#6449)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update babel-eslint to version 10.1.0 * chore(package): update lockfile package-lock.json --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03b47a94db..eff879e526 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3351,15 +3351,15 @@ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" }, "babel-eslint": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz", - "integrity": "sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", "eslint-visitor-keys": "^1.0.0", "resolve": "^1.12.0" } diff --git a/package.json b/package.json index d84b71e896..b999264125 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "apollo-link-ws": "1.0.19", "apollo-upload-client": "12.1.0", "apollo-utilities": "1.3.3", - "babel-eslint": "10.0.3", + "babel-eslint": "10.1.0", "bcrypt-nodejs": "0.0.3", "cross-env": "7.0.0", "deep-diff": "1.0.2", From 5947fc33e4f9f48b7c20a3d63f26539384bd1892 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2020 22:30:56 +0000 Subject: [PATCH 10/21] =?UTF-8?q?Update=20babel7=20to=20the=20latest=20ver?= =?UTF-8?q?sion=20=F0=9F=9A=80=20(#6450)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update @babel/core to version 7.8.6 * chore(package): update @babel/preset-env to version 7.8.6 * chore(package): update lockfile package-lock.json --- package-lock.json | 576 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 291 insertions(+), 289 deletions(-) diff --git a/package-lock.json b/package-lock.json index eff879e526..534bda6ed7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -79,9 +79,9 @@ } }, "@babel/compat-data": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.4.tgz", - "integrity": "sha512-lHLhlsvFjJAqNU71b7k6Vv9ewjmTXKvqaMv7n0G1etdCabWLw3nEYE8mmgoVOxMIFE07xOvo7H7XBASirX6Rrg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.6.tgz", + "integrity": "sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q==", "dev": true, "requires": { "browserslist": "^4.8.5", @@ -98,18 +98,18 @@ } }, "@babel/core": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz", - "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.6.tgz", + "integrity": "sha512-Sheg7yEJD51YHAvLEV/7Uvw95AeWqYPL3Vk3zGujJKIhJ+8oLw2ALaf3hbucILhKsgSoADOvtKRJuNVdcJkOrg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helpers": "^7.8.4", - "@babel/parser": "^7.8.4", - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", @@ -130,12 +130,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -182,43 +182,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -279,9 +279,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -302,9 +302,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -335,12 +335,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -387,43 +387,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -449,12 +449,12 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz", - "integrity": "sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.6.tgz", + "integrity": "sha512-UrJdk27hKVJSnibFcUWYLkCL0ZywTUoot8yii1lsHJcvwrypagmYKjHLMWivQPm4s6GdyygCL8fiH5EYLxhQwQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.8.4", + "@babel/compat-data": "^7.8.6", "browserslist": "^4.8.5", "invariant": "^2.2.4", "levenary": "^1.1.1", @@ -470,11 +470,12 @@ } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", - "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz", + "integrity": "sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A==", "dev": true, "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-regex": "^7.8.3", "regexpu-core": "^4.6.0" } @@ -531,26 +532,26 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -580,12 +581,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -632,43 +633,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -723,9 +724,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -745,9 +746,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -767,9 +768,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -780,16 +781,17 @@ } }, "@babel/helper-module-transforms": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", - "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz", + "integrity": "sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-simple-access": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.8.6", "lodash": "^4.17.13" }, "dependencies": { @@ -823,26 +825,26 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -862,9 +864,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -912,12 +914,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -964,43 +966,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1026,15 +1028,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", - "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" }, "dependencies": { "@babel/code-frame": { @@ -1047,12 +1049,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -1099,43 +1101,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1191,26 +1193,26 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1251,12 +1253,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -1303,43 +1305,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1385,12 +1387,12 @@ } }, "@babel/generator": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", - "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.6.tgz", + "integrity": "sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg==", "dev": true, "requires": { - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -1437,43 +1439,43 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/traverse": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", - "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.4", + "@babel/generator": "^7.8.6", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.4", - "@babel/types": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1717,9 +1719,9 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", - "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz", + "integrity": "sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.8.3", @@ -1727,7 +1729,7 @@ "@babel/helper-function-name": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", "@babel/helper-split-export-declaration": "^7.8.3", "globals": "^11.1.0" }, @@ -1782,26 +1784,26 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1869,9 +1871,9 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz", - "integrity": "sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz", + "integrity": "sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3" @@ -1928,26 +1930,26 @@ } }, "@babel/parser": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", - "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.6.tgz", + "integrity": "sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==", "dev": true }, "@babel/template": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", - "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -2069,9 +2071,9 @@ } }, "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -2166,13 +2168,13 @@ } }, "@babel/preset-env": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.4.tgz", - "integrity": "sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.6.tgz", + "integrity": "sha512-M5u8llV9DIVXBFB/ArIpqJuvXpO+ymxcJ6e8ZAmzeK3sQeBNOD1y+rHvHCGG4TlEmsNpIrdecsHGHT8ZCoOSJg==", "dev": true, "requires": { - "@babel/compat-data": "^7.8.4", - "@babel/helper-compilation-targets": "^7.8.4", + "@babel/compat-data": "^7.8.6", + "@babel/helper-compilation-targets": "^7.8.6", "@babel/helper-module-imports": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-proposal-async-generator-functions": "^7.8.3", @@ -2195,13 +2197,13 @@ "@babel/plugin-transform-async-to-generator": "^7.8.3", "@babel/plugin-transform-block-scoped-functions": "^7.8.3", "@babel/plugin-transform-block-scoping": "^7.8.3", - "@babel/plugin-transform-classes": "^7.8.3", + "@babel/plugin-transform-classes": "^7.8.6", "@babel/plugin-transform-computed-properties": "^7.8.3", "@babel/plugin-transform-destructuring": "^7.8.3", "@babel/plugin-transform-dotall-regex": "^7.8.3", "@babel/plugin-transform-duplicate-keys": "^7.8.3", "@babel/plugin-transform-exponentiation-operator": "^7.8.3", - "@babel/plugin-transform-for-of": "^7.8.4", + "@babel/plugin-transform-for-of": "^7.8.6", "@babel/plugin-transform-function-name": "^7.8.3", "@babel/plugin-transform-literals": "^7.8.3", "@babel/plugin-transform-member-expression-literals": "^7.8.3", @@ -2222,7 +2224,7 @@ "@babel/plugin-transform-template-literals": "^7.8.3", "@babel/plugin-transform-typeof-symbol": "^7.8.4", "@babel/plugin-transform-unicode-regex": "^7.8.3", - "@babel/types": "^7.8.3", + "@babel/types": "^7.8.6", "browserslist": "^4.8.5", "core-js-compat": "^3.6.2", "invariant": "^2.2.2", @@ -2231,9 +2233,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.6.tgz", + "integrity": "sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -3630,14 +3632,14 @@ } }, "browserslist": { - "version": "4.8.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz", - "integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.9.0.tgz", + "integrity": "sha512-seffIXhwgB84+OCeT/aMjpZnsAsYDiMSC+CEs3UkF8iU64BZGYcu+TZYs/IBpo4nRi0vJywUJWYdbTsOhFTweg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001023", - "electron-to-chromium": "^1.3.341", - "node-releases": "^1.1.47" + "caniuse-lite": "^1.0.30001030", + "electron-to-chromium": "^1.3.361", + "node-releases": "^1.1.50" } }, "bson": { @@ -3776,9 +3778,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001023", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", - "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "version": "1.0.30001030", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001030.tgz", + "integrity": "sha512-QGK0W4Ft/Ac+zTjEiRJfwDNATvS3fodDczBXrH42784kcfqcDKpEPfN08N0HQjrAp8He/Jw8QiSS9QRn7XAbUw==", "dev": true }, "caseless": { @@ -4858,9 +4860,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.344", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.344.tgz", - "integrity": "sha512-tvbx2Wl8WBR+ym3u492D0L6/jH+8NoQXqe46+QhbWH3voVPauGuZYeb1QAXYoOAWuiP2dbSvlBx0kQ1F3hu/Mw==", + "version": "1.3.363", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.363.tgz", + "integrity": "sha512-4w19wPBkeunBjOA53lNFT36IdOD3Tk1OoIDtTX+VToJUUDX42QfuhtsNKXv25wmSnoBOExM3kTbj7/WDNBwHuQ==", "dev": true }, "elegant-spinner": { @@ -9541,9 +9543,9 @@ } }, "node-releases": { - "version": "1.1.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", - "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "version": "1.1.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.50.tgz", + "integrity": "sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ==", "dev": true, "requires": { "semver": "^6.3.0" @@ -10646,9 +10648,9 @@ "dev": true }, "regjsparser": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz", - "integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.3.tgz", + "integrity": "sha512-8uZvYbnfAtEm9Ab8NTb3hdLwL4g/LQzEYP7Xs27T96abJCCE2d6r3cPZPQEsLKy0vRSGVNG+/zVGtLr86HQduA==", "dev": true, "requires": { "jsesc": "~0.5.0" diff --git a/package.json b/package.json index b999264125..8c95b6e5bf 100644 --- a/package.json +++ b/package.json @@ -59,10 +59,10 @@ }, "devDependencies": { "@babel/cli": "7.8.4", - "@babel/core": "7.8.4", + "@babel/core": "7.8.6", "@babel/plugin-proposal-object-rest-spread": "7.8.3", "@babel/plugin-transform-flow-strip-types": "7.8.3", - "@babel/preset-env": "7.8.4", + "@babel/preset-env": "7.8.6", "@parse/minami": "1.0.0", "apollo-cache-inmemory": "1.6.5", "apollo-client": "2.6.6", From 4291f2b22afb9da82c56d7eb4cfa3a2c4ed59dbb Mon Sep 17 00:00:00 2001 From: Arthur Cinader <700572+acinader@users.noreply.github.com> Date: Fri, 28 Feb 2020 15:22:38 -0800 Subject: [PATCH 11/21] Prepare for 4.0 Release (#6412) * Preparee for 3.11.0 Release * Little fixes * add in newly merge pr's into the changelog. * Remove inconsistent full stops * bump version to 4.0 * update changelog for v 4.0 * a touch of wordmsithery. * Nits Co-authored-by: Tom Fox <13188249+TomWFox@users.noreply.github.com> --- CHANGELOG.md | 31 ++++++++++++++++++++++++++----- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1488539480..45f8b9dae6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,30 @@ ## Parse Server Changelog ### master - -[Full Changelog](https://github.com/parse-community/parse-server/compare/3.10.0...master) -- FIX: FIX: Prevent new usernames or emails that clash with existing users' email or username if it only differs by case. For example, don't allow a new user with the name 'Jane' if we already have a user 'jane'. [#5634](https://github.com/parse-community/parse-server/pull/5634). Thanks to [Arthur Cinader](https://github.com/acinader) +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.0...master) + +### 4.0 +__BREAKING CHANGES:__ +1. Remove Support for Mongo 3.2 & 3.4. The new minimum supported version is Mongo 3.6. +2. Change username and email validation to be case insensitive. This change should be transparent in most use cases. The validation behavior should now behave 'as expected'. See [#6414](https://github.com/parse-community/parse-server/pull/6414) for details. + +[Full Changelog](https://github.com/parse-community/parse-server/compare/3.10.0...4.0.0) +- NEW: add hint option to Parse.Query [#6322](https://github.com/parse-community/parse-server/pull/6322). Thanks to [Steve Stencil](https://github.com/stevestencil) +- FIX: CLP objectId size validation fix [#6332](https://github.com/parse-community/parse-server/pull/6332). Thanks to [Old Grandpa](https://github.com/BufferUnderflower) +- FIX: Add volumes to Docker command [#6356](https://github.com/parse-community/parse-server/pull/6356). Thanks to [Kasra Bigdeli](https://github.com/githubsaturn) +- NEW: GraphQL 3rd Party LoginWith Support [#6371](https://github.com/parse-community/parse-server/pull/6371). Thanks to [Antoine Cormouls](https://github.com/Moumouls) +- FIX: GraphQL Geo Queries [#6363](https://github.com/parse-community/parse-server/pull/6363). Thanks to [Antoine Cormouls](https://github.com/Moumouls) +- NEW: GraphQL Nested File Upload [#6372](https://github.com/parse-community/parse-server/pull/6372). Thanks to [Antoine Cormouls](https://github.com/Moumouls) +- NEW: Granular CLP pointer permissions [#6352](https://github.com/parse-community/parse-server/pull/6352). Thanks to [Old Grandpa](https://github.com/BufferUnderflower) +- FIX: Add missing colon for customPages [#6393](https://github.com/parse-community/parse-server/pull/6393). Thanks to [Jerome De Leon](https://github.com/JeromeDeLeon) +NEW: `afterLogin` cloud code hook [#6387](https://github.com/parse-community/parse-server/pull/6387). Thanks to [David Corona](https://github.com/davesters) +- FIX: __BREAKING CHANGE__ Prevent new usernames or emails that clash with existing users' email or username if it only differs by case. For example, don't allow a new user with the name 'Jane' if we already have a user 'jane'. [#5634](https://github.com/parse-community/parse-server/pull/5634). Thanks to [Arthur Cinader](https://github.com/acinader) +- FIX: Support Travis CI V2. [#6414](https://github.com/parse-community/parse-server/pull/6414). Thanks to [Diamond Lewis](https://github.com/dplewis) +- FIX: Prevent crashing on websocket error. [#6418](https://github.com/parse-community/parse-server/pull/6418). Thanks to [Diamond Lewis](https://github.com/dplewis) +- NEW: Allow protectedFields for Authenticated users and Public. [$6415](https://github.com/parse-community/parse-server/pull/6415). Thanks to [Old Grandpa](https://github.com/BufferUnderflower) +- FIX: Correct bug in determining GraphQL pointer errors when mutating. [#6413](https://github.com/parse-community/parse-server/pull/6431). Thanks to [Antoine Cormouls](https://github.com/Moumouls) +- NEW: Allow true GraphQL Schema Customization. [#6360](https://github.com/parse-community/parse-server/pull/6360). Thanks to [Antoine Cormouls](https://github.com/Moumouls) +- __BREAKING CHANGE__: Remove Support for Mongo version < 3.6 [#6445](https://github.com/parse-community/parse-server/pull/6445). Thanks to [Arthur Cinader](https://github.com/acinader) ### 3.10.0 [Full Changelog](https://github.com/parse-community/parse-server/compare/3.9.0...3.10.0) @@ -21,8 +42,8 @@ - NEW: GraphQL: DX Relational Where Query [#6255](https://github.com/parse-community/parse-server/pull/6255). Thanks to [Antoine Cormouls](https://github.com/Moumouls) - CHANGE: test against Postgres 11 [#6260](https://github.com/parse-community/parse-server/pull/6260). Thanks to [Diamond Lewis](https://github.com/dplewis) - CHANGE: test against Postgres 11 [#6260](https://github.com/parse-community/parse-server/pull/6260). Thanks to [Diamond Lewis](https://github.com/dplewis) -- NEW: GraphQL alias for mutations in classConfigs [#6258](https://github.com/parse-community/parse-server/pull/6258). Thanks to [Old Grandpa ](https://github.com/BufferUnderflower) -- NEW: GraphQL classConfig query alias [#6257](https://github.com/parse-community/parse-server/pull/6257). Thanks to [Old Grandpa ](https://github.com/BufferUnderflower) +- NEW: GraphQL alias for mutations in classConfigs [#6258](https://github.com/parse-community/parse-server/pull/6258). Thanks to [Old Grandpa](https://github.com/BufferUnderflower) +- NEW: GraphQL classConfig query alias [#6257](https://github.com/parse-community/parse-server/pull/6257). Thanks to [Old Grandpa](https://github.com/BufferUnderflower) - NEW: Allow validateFilename to return a string or Parse Error [#6246](https://github.com/parse-community/parse-server/pull/6246). Thanks to [Mike Patnode](https://github.com/mpatnode) - NEW: Relay Spec [#6089](https://github.com/parse-community/parse-server/pull/6089). Thanks to [Antonio Davi Macedo Coelho de Castro](https://github.com/davimacedo) - CHANGE: Set default ACL for GraphQL [#6249](https://github.com/parse-community/parse-server/pull/6249). Thanks to [Antoine Cormouls](https://github.com/Moumouls) diff --git a/package-lock.json b/package-lock.json index 534bda6ed7..50d4ea8070 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "3.10.0", + "version": "4.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8c95b6e5bf..ba0149da0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "3.10.0", + "version": "4.0.0", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 6b0efaeffd9fc59002ee87562d0a4105d52d02a3 Mon Sep 17 00:00:00 2001 From: Old Grandpa Date: Sat, 29 Feb 2020 02:52:48 +0300 Subject: [PATCH 12/21] Do not allow to protect default fields (#6439) * consider default columns * disallow protecting default fields --- spec/ProtectedFields.spec.js | 24 +++++++++++++++++++++--- src/Controllers/SchemaController.js | 7 +++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/spec/ProtectedFields.spec.js b/spec/ProtectedFields.spec.js index 3794996c6e..fdc3c2d10a 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,24 @@ describe('ProtectedFields', function() { }) ).toBeResolved(); }); + + 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` + ) + ); + } + }); }); describe('targeting public access', () => { @@ -1310,10 +1328,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..435a4b5570 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -307,6 +307,13 @@ 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)) { throw new Parse.Error( From c973356a22440b549abff0c97784af721ade6fc6 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Sat, 29 Feb 2020 00:12:47 +0000 Subject: [PATCH 13/21] =?UTF-8?q?Update=20lint-staged=20to=20the=20latest?= =?UTF-8?q?=20version=20=F0=9F=9A=80=20(#6446)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update lint-staged to version 10.0.8 * chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50d4ea8070..1493ae9558 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8170,9 +8170,9 @@ } }, "lint-staged": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.7.tgz", - "integrity": "sha512-Byj0F4l7GYUpYYHEqyFH69NiI6ICTg0CeCKbhRorL+ickbzILKUlZLiyCkljZV02wnoh7yH7PmFyYm9PRNwk9g==", + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.8.tgz", + "integrity": "sha512-Oa9eS4DJqvQMVdywXfEor6F4vP+21fPHF8LUXgBbVWUSWBddjqsvO6Bv1LwMChmgQZZqwUvgJSHlu8HFHAPZmA==", "dev": true, "requires": { "chalk": "^3.0.0", diff --git a/package.json b/package.json index ba0149da0a..28f0207e9b 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "jasmine": "3.5.0", "jsdoc": "3.6.3", "jsdoc-babel": "0.5.0", - "lint-staged": "10.0.7", + "lint-staged": "10.0.8", "mongodb-runner": "4.8.0", "node-fetch": "2.6.0", "nyc": "15.0.0", From 2a5c306aa8e60f69e41a8a00d68437899526a16d Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Sat, 29 Feb 2020 00:13:48 +0000 Subject: [PATCH 14/21] =?UTF-8?q?Update=20flow-bin=20to=20the=20latest=20v?= =?UTF-8?q?ersion=20=F0=9F=9A=80=20(#6448)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update flow-bin to version 0.119.1 * chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1493ae9558..2bdb792b1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5887,9 +5887,9 @@ "dev": true }, "flow-bin": { - "version": "0.119.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.119.0.tgz", - "integrity": "sha512-fCVv++rjBsx/q6YVeB3F+A/owztjUO5PyBLwhGZdK5igVmiFQ8RKBTR9T2mb+SQRLZJJhl/xwPLhNzr3dBba6w==", + "version": "0.119.1", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.119.1.tgz", + "integrity": "sha512-mX6qjJVi7aLqR9sDf8QIHt8yYEWQbkMLw7qFoC7sM/AbJwvqFm3pATPN96thsaL9o1rrshvxJpSgoj1PJSC3KA==", "dev": true }, "follow-redirects": { diff --git a/package.json b/package.json index 28f0207e9b..500da5048c 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "deep-diff": "1.0.2", "eslint": "6.8.0", "eslint-plugin-flowtype": "4.5.0", - "flow-bin": "0.119.0", + "flow-bin": "0.119.1", "form-data": "3.0.0", "gaze": "1.1.3", "graphql-tag": "^2.10.1", From cd06a02fe8bf29796b57d0e35f8287243e0f9077 Mon Sep 17 00:00:00 2001 From: Arthur Cinader <700572+acinader@users.noreply.github.com> Date: Fri, 28 Feb 2020 17:34:19 -0800 Subject: [PATCH 15/21] skip cleanup so we don't erase babel and stuff (#6452) * skip cleanup so we don't erase babel and stuff * skip cleanup the right way! * Add change log and bump version * include one more commit * remove breaking change from non breaking change. Co-authored-by: Diamond Lewis --- .travis.yml | 6 +++--- CHANGELOG.md | 8 ++++++-- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 44e903339d..5bce5cd927 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ after_script: jobs: allow_failures: - env: NODE_VERSION=12.12.0 - include: + include: - stage: release node_js: '10' env: @@ -64,7 +64,7 @@ jobs: - "./release_docs.sh" deploy: - provider: pages - cleanup: true + cleanup: false token: secure: YU2lUqmW036AHBRu7xO/AwEeQ900Q/5O6FL96ZqWEfD7Gadaq4iapkNvhPR0HcZYRHqQV2/2LCHVnhd0dbj0ShkmVIHdQE7O+MF+j0v0GIVc8FPTPe1/d2Hy4apSWNe6FeCrYKVeliAu+ZqvNuFLhVmYvIeJdlJrMGOb6P76UZXRDv2srXhq4uBcCVUJuTajyyd5ttJfcNapymTP+xzEDYc7Hr4LJaubmv/wVD/xwPBbvfYFuBqysUpkPKi/ODlQbB0ybYh2fFnX71WUyFUGbtB5xI9ma951Zp4v3t73c31uUl27dJaHzO62EtVTdcUKAa804EtAtsvpeJWMVWKUgigm9UZcXdEwKa79fl5nLaq34lrSktAYOkexwPqYj+vbS6sn52JrluSxLE+4cEke7tYbnJ9X12SAQXKgcXY3n30+6gKf9RVqYdlNsYpEAqKVIDb6SlEkk86dP+uIg/XXb5RKEwxbDXnb6xdl9JRc+GTbeeY3/vg2h9QTdmFVblPtBhHrNenQYP/BS0n+EfUnAIBKqRmQgyhao3SiY5FMACM8higI2Lvvhpq46pDhXqsexYCz5F008C6YXGDh5gC93rJFec0pjh55DNdQu6uw3YMQ5jtf3QUXoPAoMFud3cTulMlnjC1WZG8QbqER8dzUZ4TcaQUdzribJI/mRriheBg= local_dir: docs/ @@ -75,7 +75,7 @@ jobs: secure: Yrng6jsnMAtzrrln9DwRuY4xpcxl/WYS/1A5fckyQF6DsLmNlvqVtu3MWF+zdJgANF63G3jIee11tNBpYRecHl8FjPGwO0kc1vEgvIRVnveyR0bwIIDH6s/mR9dg4rZikflwG4XExsLyaQd7ko8aTIOIayfxJiv/u0yqwuBuBW2bFrL/41b1cKGK5+Iq2a+PdFENUPenKXISkACGaMnQF4Y/KVF98UwCiGLf957yFWc2sD6TFbjNDbAENSccvg1J3fBb+djbtzKzldl29ntp2mKVGSVASiKCRa6hSfgQulHiidFqFIKgpYJ1uATRr3UFr/NRVt1WbrgLnzY74OCX7y02c/xiYQMMEPRl/P8hHJu+KjQ3PBWsBvmsRN0QMUJv3PEjUPE3AY8sw49NoxiJZzJr7574vUBuM/dk0byYI6K/gwmUrPIhQjljzZqinS8JJJ4FjGjCdzXRhT5Q+PZvt5bF1rMOZXayNJZa+cICtmiJoU3vO2Yf6TXC3wY1veKvmcs24nws5lp4keJePTKAi1Ig7VoSxwAlgs3EGANIh7oBKx9zWnXQYMdmxbYsvLXAWcnnM+PcSCvooLmXWso3BQBeRuUUSS2oLaBpsFMsiniLNbA1cW4fwMkgUGz4oEDRi8wTD89E/1J2oNxzqtWRPawcVKpMpnBbDJHrWJPEHMw= email: secure: lomzDl71N995SzRczm7VE9OZE+PzMo4X8t3zU97agu/FMH5Qcj8BLwE+uVDTnA9Vblyj62ZsFKsNjP2Qp53Vcd+jHM4EJNWNRZYpEMIRO3LngX43r83qoFEHUvPu9s1oaa04a6FojcsJx0wl6B6Ke2AX74MXnJDLb9iZBy1mkpLUMVccVhSfhdoIzhkq3dhUw+6d8C024tNMHcgDW3VnRAsWFtiL7dCMpjLOdI+UxlkeGkQkxXXuRsZ0ZdjoSoM8NSkiYMc8x6EnekyRDoHTujX3OFxuU6+GAjrUmVzNmJWrBIqHVb0DXBQxjEaG3d/cNu5UsQyZYq5sxRRH0BaLs7F4oIQg95etasEtTtUkmsZ3pshVlsweiLU366UdbfuAf5hrJjqLrU12BKZyLjaAwyeKz031r8dA4sJtGIp5uVdXobQQTH6r958A88byJ20uaYSqhqjhZo3hkWXIQP0WQN2Ej/g57HbVNLB/nPKkMILfk/tpp7nBDLT0QrjbZxeo1dwCHqsBEV6z7ZyWyFf4xwpDsir4txL4t8ElzeGdlACjCqAJvIh5w9YzfrwijtoVMvvP6pWvn/iI640d4rsdIDe8egxgqZ1R/TMd/tdHYX+eI+ZfFmCVGj36/uXwdG7KIoIZVjRQ2tvWr9ZuydEPWPSRVGT4ycFeu6wbm3elM3I= - cleanup: true + cleanup: false on: tags: true all_branches: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 45f8b9dae6..a5e013832c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,17 @@ ## Parse Server Changelog ### master -[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.0...master) +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.1...master) -### 4.0 +### 4.0.1 __BREAKING CHANGES:__ 1. Remove Support for Mongo 3.2 & 3.4. The new minimum supported version is Mongo 3.6. 2. Change username and email validation to be case insensitive. This change should be transparent in most use cases. The validation behavior should now behave 'as expected'. See [#6414](https://github.com/parse-community/parse-server/pull/6414) for details. +- FIX: correct 'new' travis config to properly deploy. See [#6452](https://github.com/parse-community/parse-server/pull/6452). Thanks to [Arthur Cinader](https://github.com/acinader). +- FIX: Better message on not allowed to protect default fields. See [#6439](https://github.com/parse-community/parse-server/pull/6439).Thanks to [Old Grandpa](https://github.com/BufferUnderflower) + +### 4.0 [Full Changelog](https://github.com/parse-community/parse-server/compare/3.10.0...4.0.0) - NEW: add hint option to Parse.Query [#6322](https://github.com/parse-community/parse-server/pull/6322). Thanks to [Steve Stencil](https://github.com/stevestencil) - FIX: CLP objectId size validation fix [#6332](https://github.com/parse-community/parse-server/pull/6332). Thanks to [Old Grandpa](https://github.com/BufferUnderflower) diff --git a/package-lock.json b/package-lock.json index 2bdb792b1a..f31c892ce8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "4.0.0", + "version": "4.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 500da5048c..713d918d3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "4.0.0", + "version": "4.0.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From cfb0327c19901d4788d9f3983845c69198dffa8d Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 16:49:23 +0000 Subject: [PATCH 16/21] =?UTF-8?q?Update=20bcrypt=20to=20the=20latest=20ver?= =?UTF-8?q?sion=20=F0=9F=9A=80=20(#6456)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update bcrypt to version 4.0.1 * chore(package): update lockfile package-lock.json --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index f31c892ce8..a44ec8d9f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3459,9 +3459,9 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bcrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-4.0.0.tgz", - "integrity": "sha512-UroxVJgmpeek3uxjY0IgtVtegM8EQqSLXnc5HE59m388MGZr0wPpRBqKJTaTraY3YEJOo1XIczExiEY9eeOCmg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-4.0.1.tgz", + "integrity": "sha512-hSIZHkUxIDS5zA2o00Kf2O5RfVbQ888n54xQoF/eIaquU4uaLxK8vhhBdktd0B3n2MjkcAWzv4mnhogykBKOUQ==", "optional": true, "requires": { "node-addon-api": "^2.0.0", @@ -9450,9 +9450,9 @@ "optional": true }, "needle": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.2.tgz", - "integrity": "sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.3.tgz", + "integrity": "sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw==", "optional": true, "requires": { "debug": "^3.2.6", diff --git a/package.json b/package.json index 713d918d3d..f7b6732ea5 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "parse-server": "./bin/parse-server" }, "optionalDependencies": { - "bcrypt": "4.0.0" + "bcrypt": "4.0.1" }, "collective": { "type": "opencollective", From bde8ab6d55e4da556d0e77eb29d4953ca34eeace Mon Sep 17 00:00:00 2001 From: Arthur Cinader <700572+acinader@users.noreply.github.com> Date: Mon, 2 Mar 2020 10:46:07 -0800 Subject: [PATCH 17/21] Attempt to get Travis to deploy to npmjs (#6457) * Use deprecated skip_cleanup as cleanup: false doesn't appear to be working * prepare release * revert change to branch --- .travis.yml | 5 +++-- CHANGELOG.md | 9 +++++++-- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5bce5cd927..f5383e20e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ branches: - master - "/^[0-9]+.[0-9]+.[0-9]+(-.*)?$/" - 3.x + - 4.x - "/^greenkeeper/.*$/" cache: directories: @@ -64,18 +65,18 @@ jobs: - "./release_docs.sh" deploy: - provider: pages - cleanup: false + skip_cleanup: true token: secure: YU2lUqmW036AHBRu7xO/AwEeQ900Q/5O6FL96ZqWEfD7Gadaq4iapkNvhPR0HcZYRHqQV2/2LCHVnhd0dbj0ShkmVIHdQE7O+MF+j0v0GIVc8FPTPe1/d2Hy4apSWNe6FeCrYKVeliAu+ZqvNuFLhVmYvIeJdlJrMGOb6P76UZXRDv2srXhq4uBcCVUJuTajyyd5ttJfcNapymTP+xzEDYc7Hr4LJaubmv/wVD/xwPBbvfYFuBqysUpkPKi/ODlQbB0ybYh2fFnX71WUyFUGbtB5xI9ma951Zp4v3t73c31uUl27dJaHzO62EtVTdcUKAa804EtAtsvpeJWMVWKUgigm9UZcXdEwKa79fl5nLaq34lrSktAYOkexwPqYj+vbS6sn52JrluSxLE+4cEke7tYbnJ9X12SAQXKgcXY3n30+6gKf9RVqYdlNsYpEAqKVIDb6SlEkk86dP+uIg/XXb5RKEwxbDXnb6xdl9JRc+GTbeeY3/vg2h9QTdmFVblPtBhHrNenQYP/BS0n+EfUnAIBKqRmQgyhao3SiY5FMACM8higI2Lvvhpq46pDhXqsexYCz5F008C6YXGDh5gC93rJFec0pjh55DNdQu6uw3YMQ5jtf3QUXoPAoMFud3cTulMlnjC1WZG8QbqER8dzUZ4TcaQUdzribJI/mRriheBg= local_dir: docs/ on: all_branches: true - provider: npm + skip_cleanup: true api_token: secure: Yrng6jsnMAtzrrln9DwRuY4xpcxl/WYS/1A5fckyQF6DsLmNlvqVtu3MWF+zdJgANF63G3jIee11tNBpYRecHl8FjPGwO0kc1vEgvIRVnveyR0bwIIDH6s/mR9dg4rZikflwG4XExsLyaQd7ko8aTIOIayfxJiv/u0yqwuBuBW2bFrL/41b1cKGK5+Iq2a+PdFENUPenKXISkACGaMnQF4Y/KVF98UwCiGLf957yFWc2sD6TFbjNDbAENSccvg1J3fBb+djbtzKzldl29ntp2mKVGSVASiKCRa6hSfgQulHiidFqFIKgpYJ1uATRr3UFr/NRVt1WbrgLnzY74OCX7y02c/xiYQMMEPRl/P8hHJu+KjQ3PBWsBvmsRN0QMUJv3PEjUPE3AY8sw49NoxiJZzJr7574vUBuM/dk0byYI6K/gwmUrPIhQjljzZqinS8JJJ4FjGjCdzXRhT5Q+PZvt5bF1rMOZXayNJZa+cICtmiJoU3vO2Yf6TXC3wY1veKvmcs24nws5lp4keJePTKAi1Ig7VoSxwAlgs3EGANIh7oBKx9zWnXQYMdmxbYsvLXAWcnnM+PcSCvooLmXWso3BQBeRuUUSS2oLaBpsFMsiniLNbA1cW4fwMkgUGz4oEDRi8wTD89E/1J2oNxzqtWRPawcVKpMpnBbDJHrWJPEHMw= email: secure: lomzDl71N995SzRczm7VE9OZE+PzMo4X8t3zU97agu/FMH5Qcj8BLwE+uVDTnA9Vblyj62ZsFKsNjP2Qp53Vcd+jHM4EJNWNRZYpEMIRO3LngX43r83qoFEHUvPu9s1oaa04a6FojcsJx0wl6B6Ke2AX74MXnJDLb9iZBy1mkpLUMVccVhSfhdoIzhkq3dhUw+6d8C024tNMHcgDW3VnRAsWFtiL7dCMpjLOdI+UxlkeGkQkxXXuRsZ0ZdjoSoM8NSkiYMc8x6EnekyRDoHTujX3OFxuU6+GAjrUmVzNmJWrBIqHVb0DXBQxjEaG3d/cNu5UsQyZYq5sxRRH0BaLs7F4oIQg95etasEtTtUkmsZ3pshVlsweiLU366UdbfuAf5hrJjqLrU12BKZyLjaAwyeKz031r8dA4sJtGIp5uVdXobQQTH6r958A88byJ20uaYSqhqjhZo3hkWXIQP0WQN2Ej/g57HbVNLB/nPKkMILfk/tpp7nBDLT0QrjbZxeo1dwCHqsBEV6z7ZyWyFf4xwpDsir4txL4t8ElzeGdlACjCqAJvIh5w9YzfrwijtoVMvvP6pWvn/iI640d4rsdIDe8egxgqZ1R/TMd/tdHYX+eI+ZfFmCVGj36/uXwdG7KIoIZVjRQ2tvWr9ZuydEPWPSRVGT4ycFeu6wbm3elM3I= - cleanup: false on: tags: true all_branches: true diff --git a/CHANGELOG.md b/CHANGELOG.md index a5e013832c..551ea19772 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,18 @@ ## Parse Server Changelog ### master -[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.1...master) +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.2...master) -### 4.0.1 +### 4.0.2 +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.1...4.0.2) __BREAKING CHANGES:__ 1. Remove Support for Mongo 3.2 & 3.4. The new minimum supported version is Mongo 3.6. 2. Change username and email validation to be case insensitive. This change should be transparent in most use cases. The validation behavior should now behave 'as expected'. See [#6414](https://github.com/parse-community/parse-server/pull/6414) for details. +FIX: attempt to get travis to deploy to npmjs again. See [#6475](https://github.com/parse-community/parse-server/pull/6457). Thanks to [Arthur Cinader](https://github.com/acinader). + +### 4.0.1 +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.0...4.0.1) - FIX: correct 'new' travis config to properly deploy. See [#6452](https://github.com/parse-community/parse-server/pull/6452). Thanks to [Arthur Cinader](https://github.com/acinader). - FIX: Better message on not allowed to protect default fields. See [#6439](https://github.com/parse-community/parse-server/pull/6439).Thanks to [Old Grandpa](https://github.com/BufferUnderflower) diff --git a/package-lock.json b/package-lock.json index a44ec8d9f3..25a51c57cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "4.0.1", + "version": "4.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f7b6732ea5..c2d4e04f82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "4.0.1", + "version": "4.0.2", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 3a3a5eee5ffa48da1352423312cb767de14de269 Mon Sep 17 00:00:00 2001 From: Arthur Cinader <700572+acinader@users.noreply.github.com> Date: Mon, 2 Mar 2020 15:46:01 -0800 Subject: [PATCH 18/21] Merge pull request from GHSA-h4mf-75hf-67w4 * Fix session token issue * verify email problem * Fix password reset problem * Change test file name * Split tests * Refetch user * Replaces lets to consts * Refactor unit test What you have is just finee, but wanted to show you what I meant with my comment Use jasmine's this to set stuff in beforeEach's Not that all functions need to be `function ()` instead of `() =>` so `this` is preserved. see: https://jasmine.github.io/tutorials/your_first_suite#section-The_%3Ccode%3Ethis%3C/code%3E_keyword Co-authored-by: Antonio Davi Macedo Coelho de Castro --- spec/RegexVulnerabilities.spec.js | 198 ++++++++++++++++++++++++++++++ src/Routers/PublicAPIRouter.js | 13 +- src/middlewares.js | 4 + 3 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 spec/RegexVulnerabilities.spec.js diff --git a/spec/RegexVulnerabilities.spec.js b/spec/RegexVulnerabilities.spec.js new file mode 100644 index 0000000000..58f5afac92 --- /dev/null +++ b/spec/RegexVulnerabilities.spec.js @@ -0,0 +1,198 @@ +const request = require('../lib/request'); + +const serverURL = 'http://localhost:8378/1'; +const headers = { + 'Content-Type': 'application/json', +}; +const keys = { + _ApplicationId: 'test', + _JavaScriptKey: 'test', +}; +const emailAdapter = { + sendVerificationEmail: () => Promise.resolve(), + sendPasswordResetEmail: () => Promise.resolve(), + sendMail: () => {}, +}; +const appName = 'test'; +const publicServerURL = 'http://localhost:8378/1'; + +describe('Regex Vulnerabilities', function() { + beforeEach(async function() { + await reconfigureServer({ + verifyUserEmails: true, + emailAdapter, + appName, + publicServerURL, + }); + + const signUpResponse = await request({ + url: `${serverURL}/users`, + method: 'POST', + headers, + body: JSON.stringify({ + ...keys, + _method: 'POST', + username: 'someemail@somedomain.com', + password: 'somepassword', + email: 'someemail@somedomain.com', + }), + }); + this.objectId = signUpResponse.data.objectId; + this.sessionToken = signUpResponse.data.sessionToken; + this.partialSessionToken = this.sessionToken.slice(0, 3); + }); + + describe('on session token', function() { + it('should not work with regex', async function() { + try { + await request({ + url: `${serverURL}/users/me`, + method: 'POST', + headers, + body: JSON.stringify({ + ...keys, + _SessionToken: { + $regex: this.partialSessionToken, + }, + _method: 'GET', + }), + }); + fail('should not work'); + } catch (e) { + expect(e.data.code).toEqual(209); + expect(e.data.error).toEqual('Invalid session token'); + } + }); + + it('should work with plain token', async function() { + const meResponse = await request({ + url: `${serverURL}/users/me`, + method: 'POST', + headers, + body: JSON.stringify({ + ...keys, + _SessionToken: this.sessionToken, + _method: 'GET', + }), + }); + expect(meResponse.data.objectId).toEqual(this.objectId); + expect(meResponse.data.sessionToken).toEqual(this.sessionToken); + }); + }); + + describe('on verify e-mail', function() { + beforeEach(async function() { + const userQuery = new Parse.Query(Parse.User); + this.user = await userQuery.get(this.objectId, { useMasterKey: true }); + }); + + it('should not work with regex', async function() { + expect(this.user.get('emailVerified')).toEqual(false); + await request({ + url: `${serverURL}/apps/test/verify_email?username=someemail@somedomain.com&token[$regex]=`, + method: 'GET', + }); + await this.user.fetch({ useMasterKey: true }); + expect(this.user.get('emailVerified')).toEqual(false); + }); + + it('should work with plain token', async function() { + expect(this.user.get('emailVerified')).toEqual(false); + // It should work + await request({ + url: `${serverURL}/apps/test/verify_email?username=someemail@somedomain.com&token=${this.user.get( + '_email_verify_token' + )}`, + method: 'GET', + }); + await this.user.fetch({ useMasterKey: true }); + expect(this.user.get('emailVerified')).toEqual(true); + }); + }); + + describe('on password reset', function() { + beforeEach(async function() { + this.user = await Parse.User.logIn( + 'someemail@somedomain.com', + 'somepassword' + ); + }); + + it('should not work with regex', async function() { + expect(this.user.id).toEqual(this.objectId); + await request({ + url: `${serverURL}/requestPasswordReset`, + method: 'POST', + headers, + body: JSON.stringify({ + ...keys, + _method: 'POST', + email: 'someemail@somedomain.com', + }), + }); + await this.user.fetch({ useMasterKey: true }); + const passwordResetResponse = await request({ + url: `${serverURL}/apps/test/request_password_reset?username=someemail@somedomain.com&token[$regex]=`, + method: 'GET', + }); + expect(passwordResetResponse.status).toEqual(302); + expect(passwordResetResponse.headers.location).toMatch( + `\\/invalid\\_link\\.html` + ); + await request({ + url: `${serverURL}/apps/test/request_password_reset`, + method: 'POST', + body: { + token: { $regex: '' }, + username: 'someemail@somedomain.com', + new_password: 'newpassword', + }, + }); + try { + await Parse.User.logIn('someemail@somedomain.com', 'newpassword'); + fail('should not work'); + } catch (e) { + expect(e.code).toEqual(101); + expect(e.message).toEqual('Invalid username/password.'); + } + }); + + it('should work with plain token', async function() { + expect(this.user.id).toEqual(this.objectId); + await request({ + url: `${serverURL}/requestPasswordReset`, + method: 'POST', + headers, + body: JSON.stringify({ + ...keys, + _method: 'POST', + email: 'someemail@somedomain.com', + }), + }); + await this.user.fetch({ useMasterKey: true }); + const token = this.user.get('_perishable_token'); + const passwordResetResponse = await request({ + url: `${serverURL}/apps/test/request_password_reset?username=someemail@somedomain.com&token=${token}`, + method: 'GET', + }); + expect(passwordResetResponse.status).toEqual(302); + expect(passwordResetResponse.headers.location).toMatch( + `\\/choose\\_password\\?token\\=${token}\\&` + ); + await request({ + url: `${serverURL}/apps/test/request_password_reset`, + method: 'POST', + body: { + token, + username: 'someemail@somedomain.com', + new_password: 'newpassword', + }, + }); + const userAgain = await Parse.User.logIn( + 'someemail@somedomain.com', + 'newpassword' + ); + expect(userAgain.id).toEqual(this.objectId); + }); + }); +}); diff --git a/src/Routers/PublicAPIRouter.js b/src/Routers/PublicAPIRouter.js index f30c52892f..7453835473 100644 --- a/src/Routers/PublicAPIRouter.js +++ b/src/Routers/PublicAPIRouter.js @@ -11,7 +11,10 @@ const views = path.resolve(__dirname, '../../views'); export class PublicAPIRouter extends PromiseRouter { verifyEmail(req) { - const { token, username } = req.query; + const { username, token: rawToken } = req.query; + const token = + rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken; + const appId = req.params.appId; const config = Config.get(appId); @@ -122,7 +125,9 @@ export class PublicAPIRouter extends PromiseRouter { return this.missingPublicServerURL(); } - const { username, token } = req.query; + const { username, token: rawToken } = req.query; + const token = + rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken; if (!username || !token) { return this.invalidLink(req); @@ -158,7 +163,9 @@ export class PublicAPIRouter extends PromiseRouter { return this.missingPublicServerURL(); } - const { username, token, new_password } = req.body; + const { username, new_password, token: rawToken } = req.body; + const token = + rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken; if ((!username || !token || !new_password) && req.xhr === false) { return this.invalidLink(req); diff --git a/src/middlewares.js b/src/middlewares.js index 75923e713f..f60cb53df6 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -105,6 +105,10 @@ export function handleParseHeaders(req, res, next) { } } + if (info.sessionToken && typeof info.sessionToken !== 'string') { + info.sessionToken = info.sessionToken.toString(); + } + if (info.clientVersion) { info.clientSDK = ClientSDK.fromString(info.clientVersion); } From b9742b6fb9298c18c30d488dd080c3e962d603eb Mon Sep 17 00:00:00 2001 From: Arthur Cinader <700572+acinader@users.noreply.github.com> Date: Tue, 3 Mar 2020 11:41:24 -0800 Subject: [PATCH 19/21] Prep 4.1 (#6462) * increment version in prep for 4.1 * changelog for 4.1 * fix security doc link Co-authored-by: Tom Fox <13188249+TomWFox@users.noreply.github.com> --- CHANGELOG.md | 7 ++++++- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 551ea19772..157b2bd0b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ## Parse Server Changelog ### master -[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.2...master) +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.1.0...master) + +### 4.1.0 +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.2...4.1.0) +_SECURITY RELEASE_: see [advisory](https://github.com/parse-community/parse-server/security/advisories/GHSA-h4mf-75hf-67w4) for details +- SECURITY FIX: Patch Regex vulnerabilities. See [3a3a5ee](https://github.com/parse-community/parse-server/commit/3a3a5eee5ffa48da1352423312cb767de14de269). Special thanks to [W0lfw00d](https://github.com/W0lfw00d) for identifying and [responsibly reporting](https://github.com/parse-community/parse-server/blob/master/SECURITY.md) the vulnerability. Thanks to [Antonio Davi Macedo Coelho de Castro](https://github.com/davimacedo) for the speedy fix. ### 4.0.2 [Full Changelog](https://github.com/parse-community/parse-server/compare/4.0.1...4.0.2) diff --git a/package-lock.json b/package-lock.json index 25a51c57cf..10e584cb66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "4.0.2", + "version": "4.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c2d4e04f82..57d530cac8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "4.0.2", + "version": "4.1.0", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 9f1af7236326fb75be96e44869ac9e41e2ba26f2 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2020 22:22:57 +0000 Subject: [PATCH 20/21] =?UTF-8?q?Update=20cross-env=20to=20the=20latest=20?= =?UTF-8?q?version=20=F0=9F=9A=80=20(#6461)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update cross-env to version 7.0.1 * chore(package): update lockfile package-lock.json --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 10e584cb66..e8ba0ddadd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4300,9 +4300,9 @@ } }, "cross-env": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.0.tgz", - "integrity": "sha512-rV6M9ldNgmwP7bx5u6rZsTbYidzwvrwIYZnT08hSGLcQCcggofgFW+sNe7IhA1SRauPS0QuLbbX+wdNtpqE5CQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.1.tgz", + "integrity": "sha512-1+DmLosu38kC4s1H4HzNkcolwdANifu9+5bE6uKQCV4L6jvVdV9qdRAk8vV3GoWRe0x4z+K2fFhgoDMqwNsPqQ==", "dev": true, "requires": { "cross-spawn": "^7.0.1" diff --git a/package.json b/package.json index 57d530cac8..6c0345fedb 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "apollo-utilities": "1.3.3", "babel-eslint": "10.1.0", "bcrypt-nodejs": "0.0.3", - "cross-env": "7.0.0", + "cross-env": "7.0.1", "deep-diff": "1.0.2", "eslint": "6.8.0", "eslint-plugin-flowtype": "4.5.0", From 209d6f7744d4b055a4af39a664396014e71f78b0 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2020 22:41:01 +0000 Subject: [PATCH 21/21] =?UTF-8?q?Update=20apollo-server=20to=20the=20lates?= =?UTF-8?q?t=20version=20=F0=9F=9A=80=20(#6460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(package): update apollo-server-express to version 2.11.0 * chore(package): update lockfile package-lock.json --- package-lock.json | 106 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8ba0ddadd..36d463bbb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,9 +25,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.15.tgz", - "integrity": "sha512-daFGV9GSs6USfPgxceDA8nlSe48XrVCJfDeYm7eokxq/ye7iuOH87hKXgMtEAVLFapkczbZsx868PMDT1Y0a6A==" + "version": "10.17.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.17.tgz", + "integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==" } } }, @@ -2538,9 +2538,9 @@ } }, "@types/body-parser": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", - "integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", "requires": { "@types/connect": "*", "@types/node": "*" @@ -2628,9 +2628,9 @@ "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==" }, "@types/koa": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.11.1.tgz", - "integrity": "sha512-/kqQs+8Qd9GL0cdl39HEhK91k7xq6+Zci76RUdqtTLj1Mg1aVG7zwJm3snkeyFUeAvY8noY27eMXgqg1wHZgwA==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.11.2.tgz", + "integrity": "sha512-2UPelagNNW6bnc1I5kIzluCaheXRA9S+NyOdXEFFj9Az7jc15ek5V03kb8OTbb3tdZ5i2BIJObe86PhHvpMolg==", "requires": { "@types/accepts": "*", "@types/cookies": "*", @@ -2881,12 +2881,12 @@ } }, "apollo-cache-control": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.8.11.tgz", - "integrity": "sha512-8yz4qbRBIFDWRHdT8uPh0HHh+VbQXxoFGJQRAG8hyMRvR+EuURXX1ltXYkn5J3YJ3MKEqgsvwGaq60dFZq63UQ==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.9.0.tgz", + "integrity": "sha512-iLT6IT4Ul5cMfBcJAvhpk3a7AD6fXqvFxNmJEPVapVJHbSKYIjra4PTis13sOyN5Y3WQS6a+NRFxAW8+hL3q3Q==", "requires": { "apollo-server-env": "^2.4.3", - "graphql-extensions": "^0.10.10" + "graphql-extensions": "^0.11.0" } }, "apollo-cache-inmemory": { @@ -2928,18 +2928,18 @@ } }, "apollo-engine-reporting": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.6.0.tgz", - "integrity": "sha512-prA17Tp/WYBJdCd4ey1CnGX8d4Xis1n9PsFmT7x8PV/oNpxG21/x3yNw5kPBZuKAoKz8yEggYtHhkYie1ZBjPQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.7.0.tgz", + "integrity": "sha512-jsjSnoHrRmk4XXK4aFU17YSJILmWsilKRwIeN74QJsSxjn5SCVF4EI/ebf/MNrTHpft8EhShx+wdkAcOD9ivqA==", "requires": { "apollo-engine-reporting-protobuf": "^0.4.4", "apollo-graphql": "^0.4.0", "apollo-server-caching": "^0.5.1", "apollo-server-env": "^2.4.3", - "apollo-server-errors": "^2.3.4", - "apollo-server-types": "^0.2.10", + "apollo-server-errors": "^2.4.0", + "apollo-server-types": "^0.3.0", "async-retry": "^1.2.1", - "graphql-extensions": "^0.10.10" + "graphql-extensions": "^0.11.0" } }, "apollo-engine-reporting-protobuf": { @@ -3022,25 +3022,25 @@ } }, "apollo-server-core": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.10.1.tgz", - "integrity": "sha512-BVITSJRMnj+CWFkjt7FMcaoqg/Ni9gfyVE9iu8bUc1IebBfFDcQj652Iolr7dTqyUziN2jbf0wfcybKYJLQHQQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.11.0.tgz", + "integrity": "sha512-jHLOqwTRlyWzqWNRlwr2M/xfrt+lw2pHtKYyxUGRjWFo8EM5TX1gDcTKtbtvx9p5m+ZBDAhcWp/rpq0vSz4tqg==", "requires": { "@apollographql/apollo-tools": "^0.4.3", "@apollographql/graphql-playground-html": "1.6.24", "@types/graphql-upload": "^8.0.0", "@types/ws": "^6.0.0", - "apollo-cache-control": "^0.8.11", + "apollo-cache-control": "^0.9.0", "apollo-datasource": "^0.7.0", - "apollo-engine-reporting": "^1.6.0", + "apollo-engine-reporting": "^1.7.0", "apollo-server-caching": "^0.5.1", "apollo-server-env": "^2.4.3", - "apollo-server-errors": "^2.3.4", - "apollo-server-plugin-base": "^0.6.10", - "apollo-server-types": "^0.2.10", - "apollo-tracing": "^0.8.11", + "apollo-server-errors": "^2.4.0", + "apollo-server-plugin-base": "^0.7.0", + "apollo-server-types": "^0.3.0", + "apollo-tracing": "^0.9.0", "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "^0.10.10", + "graphql-extensions": "^0.11.0", "graphql-tag": "^2.9.2", "graphql-tools": "^4.0.0", "graphql-upload": "^8.0.2", @@ -3085,23 +3085,23 @@ } }, "apollo-server-errors": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.3.4.tgz", - "integrity": "sha512-Y0PKQvkrb2Kd18d1NPlHdSqmlr8TgqJ7JQcNIfhNDgdb45CnqZlxL1abuIRhr8tiw8OhVOcFxz2KyglBi8TKdA==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.4.0.tgz", + "integrity": "sha512-ZouZfr2sGavvI18rgdRcyY2ausRAlVtWNOax9zca8ZG2io86dM59jXBmUVSNlVZSmBsIh45YxYC0eRvr2vmRdg==" }, "apollo-server-express": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.10.1.tgz", - "integrity": "sha512-NkuWGBOCTiju/aDjfvDImm+4yzfrM0dwiRxu9fKwwh2h1oYBUKJNqjQ1mzJRi0ks6Sn1egwl/fQkTBTkWwGx7Q==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.11.0.tgz", + "integrity": "sha512-9bbiD+zFAx+xyurc9lxYmNa9y79k/gsA1vEyPFVcv7jxzCFC5wc0tcbV7NPX2qi1Nn7K76fxo2fPNYbPFX/y0g==", "requires": { "@apollographql/graphql-playground-html": "1.6.24", "@types/accepts": "^1.3.5", - "@types/body-parser": "1.17.1", + "@types/body-parser": "1.19.0", "@types/cors": "^2.8.4", "@types/express": "4.17.2", "accepts": "^1.3.5", - "apollo-server-core": "^2.10.1", - "apollo-server-types": "^0.2.10", + "apollo-server-core": "^2.11.0", + "apollo-server-types": "^0.3.0", "body-parser": "^1.18.3", "cors": "^2.8.4", "express": "^4.17.1", @@ -3113,17 +3113,17 @@ } }, "apollo-server-plugin-base": { - "version": "0.6.10", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.6.10.tgz", - "integrity": "sha512-/xT7UT/tbCDIoTQ4lcEQsJ0ACh7h7QG0BDmeSlDXjwDuENRI50bQ2QoluCMPitZXGe+FCQfLhvzFgzbsZGT0IA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.7.0.tgz", + "integrity": "sha512-//xgYrBYLQSr92W0z3mYsFGoVz3wxKNsv3KcOUBhbOCGTbjZgP7vHOE1vhHhRcpZKKXmjXTVONdrnNJ+XVGi6A==", "requires": { - "apollo-server-types": "^0.2.10" + "apollo-server-types": "^0.3.0" } }, "apollo-server-types": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.2.10.tgz", - "integrity": "sha512-ke9ViPEWfW+2XLe66CaKGVZdS7duSLbamSKSprmmeMBd8s6tmjf0FumUVxV7X4quxPZi0OPo8x0LoLU7GWsmaA==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.3.0.tgz", + "integrity": "sha512-FMo7kbTkhph9dfIQ3xDbRLObqmdQH9mwSjxhGsX+JxGMRPPXgd3+GZvCeVKOi/udxh//w1otSeAqItjvbj0tfQ==", "requires": { "apollo-engine-reporting-protobuf": "^0.4.4", "apollo-server-caching": "^0.5.1", @@ -3131,12 +3131,12 @@ } }, "apollo-tracing": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.8.11.tgz", - "integrity": "sha512-Z0wDZ5QOBmpGoajB74ZKGTM7GzG6rqZRzAph4kxud6axcyNqUDKiKZ3Eere+NSLwvvt8M3qnPW4UJSUy/wwOXg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.9.0.tgz", + "integrity": "sha512-oqspTrf4BLGbKkIk1vF+I31C2v7PPJmF36TFpT/+zJxNvJw54ji4ZMhtytgVqbVldQEintJmdHQIidYBGKmu+g==", "requires": { "apollo-server-env": "^2.4.3", - "graphql-extensions": "^0.10.10" + "graphql-extensions": "^0.11.0" } }, "apollo-upload-client": { @@ -6832,13 +6832,13 @@ } }, "graphql-extensions": { - "version": "0.10.10", - "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.10.10.tgz", - "integrity": "sha512-pNb1DmUk6vsGtCjCRecpKoXadKNMyKxyLyE9IX65N9aKSmLL+AF7dJOOc4MWhdaAXlzxaDDhe54GpaOfoH7AOw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.11.0.tgz", + "integrity": "sha512-zd4qfUiJoYBx2MwJusM36SEJ+YmJ1ki8YF8nlm9mgaPDUzsnmFq4lxULxUfhLAXFwZw7MbEN2vV4V6WiNgSJLg==", "requires": { "@apollographql/apollo-tools": "^0.4.3", "apollo-server-env": "^2.4.3", - "apollo-server-types": "^0.2.10" + "apollo-server-types": "^0.3.0" } }, "graphql-list-fields": { diff --git a/package.json b/package.json index 6c0345fedb..d5e58a5103 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@parse/push-adapter": "3.2.0", "@parse/s3-files-adapter": "1.4.0", "@parse/simple-mailgun-adapter": "1.1.0", - "apollo-server-express": "2.10.1", + "apollo-server-express": "2.11.0", "bcryptjs": "2.4.3", "body-parser": "1.19.0", "commander": "4.1.1",