From a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Wed, 20 Sep 2023 03:47:35 -0500 Subject: [PATCH 01/33] feat: Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` (#8724) --- spec/CloudCode.spec.js | 4 ++-- spec/ParseUser.spec.js | 30 ++++++++++++++++++++++++++++++ src/Routers/UsersRouter.js | 6 ++++-- src/triggers.js | 2 ++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 14a64c4df4..37ab6a0c32 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3327,7 +3327,7 @@ describe('beforeLogin hook', () => { expect(req.headers).toBeDefined(); expect(req.ip).toBeDefined(); expect(req.installationId).toBeDefined(); - expect(req.context).toBeUndefined(); + expect(req.context).toBeDefined(); }); await Parse.User.signUp('tupac', 'shakur'); @@ -3444,7 +3444,7 @@ describe('afterLogin hook', () => { expect(req.headers).toBeDefined(); expect(req.ip).toBeDefined(); expect(req.installationId).toBeDefined(); - expect(req.context).toBeUndefined(); + expect(req.context).toBeDefined(); }); await Parse.User.signUp('testuser', 'p@ssword'); diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index 4d3beaf349..99439e3803 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -107,6 +107,36 @@ describe('Parse.User testing', () => { } }); + it('user login with context', async () => { + let hit = 0; + const context = { foo: 'bar' }; + Parse.Cloud.beforeLogin(req => { + expect(req.context).toEqual(context); + hit++; + }); + Parse.Cloud.afterLogin(req => { + expect(req.context).toEqual(context); + hit++; + }); + await Parse.User.signUp('asdf', 'zxcv'); + await request({ + method: 'POST', + url: 'http://localhost:8378/1/login', + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-REST-API-Key': 'rest', + 'X-Parse-Cloud-Context': JSON.stringify(context), + 'Content-Type': 'application/json', + }, + body: { + _method: 'GET', + username: 'asdf', + password: 'zxcv', + }, + }); + expect(hit).toBe(2); + }); + it('user login with non-string username with REST API', async done => { await Parse.User.signUp('asdf', 'zxcv'); request({ diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index 14131cf5f1..a0a801c09a 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -259,7 +259,8 @@ export class UsersRouter extends ClassesRouter { req.auth, Parse.User.fromJSON(Object.assign({ className: '_User' }, user)), null, - req.config + req.config, + req.info.context ); // If we have some new validated authData update directly @@ -291,7 +292,8 @@ export class UsersRouter extends ClassesRouter { { ...req.auth, user: afterLoginUser }, afterLoginUser, null, - req.config + req.config, + req.info.context ); if (authDataResponse) { diff --git a/src/triggers.js b/src/triggers.js index b5f11435df..5c4755af54 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -270,6 +270,8 @@ export function getRequestObject( triggerType === Types.afterSave || triggerType === Types.beforeDelete || triggerType === Types.afterDelete || + triggerType === Types.beforeLogin || + triggerType === Types.afterLogin || triggerType === Types.afterFind ) { // Set a copy of the context on the request object. From 4945ab7520b7db4169ee716fef83dffaf2dc3ac4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 20 Sep 2023 08:48:52 +0000 Subject: [PATCH 02/33] chore(release): 6.4.0-alpha.1 [skip ci] # [6.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-alpha.1) (2023-09-20) ### Bug Fixes * Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) * Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) * Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) * Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) ### Features * Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) * Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) * Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) * Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) ### Performance Improvements * Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) --- changelogs/CHANGELOG_alpha.md | 21 +++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 376b57c90d..24726e5f67 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,24 @@ +# [6.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-alpha.1) (2023-09-20) + + +### Bug Fixes + +* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) +* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) +* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) +* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) + +### Features + +* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) +* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) +* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) +* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) + +### Performance Improvements + +* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) + # [6.3.0-alpha.9](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.8...6.3.0-alpha.9) (2023-09-13) diff --git a/package-lock.json b/package-lock.json index 5e831afe3e..082b5ac759 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-beta.1", + "version": "6.4.0-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-beta.1", + "version": "6.4.0-alpha.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 4a7bb746dd..c51fcd22b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-beta.1", + "version": "6.4.0-alpha.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 39a91d0d77253fc234dd1e723fc22169d91c99a2 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:13:03 +0200 Subject: [PATCH 03/33] docs: fix incorrect alpha changelog (#8756) --- changelogs/CHANGELOG_alpha.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 24726e5f67..e3f679c6a0 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,23 +1,8 @@ # [6.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-alpha.1) (2023-09-20) - -### Bug Fixes - -* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) -* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) -* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) -* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) - ### Features -* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) * Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) -* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) -* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) - -### Performance Improvements - -* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) # [6.3.0-alpha.9](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.8...6.3.0-alpha.9) (2023-09-13) From 71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 03:22:33 +0200 Subject: [PATCH 04/33] fix: Security upgrade graphql from 16.6.0 to 16.8.1 (#8758) --- 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 082b5ac759..ec0c49e339 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "express": "4.18.2", "express-rate-limit": "6.7.0", "follow-redirects": "1.15.2", - "graphql": "16.6.0", + "graphql": "16.8.1", "graphql-list-fields": "2.0.2", "graphql-relay": "0.10.0", "graphql-tag": "2.12.6", @@ -8593,9 +8593,9 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, "node_modules/graphql": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", - "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -27130,9 +27130,9 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, "graphql": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", - "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==" + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==" }, "graphql-list-fields": { "version": "2.0.2", diff --git a/package.json b/package.json index c51fcd22b2..7c35bd61a6 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "express": "4.18.2", "express-rate-limit": "6.7.0", "follow-redirects": "1.15.2", - "graphql": "16.6.0", + "graphql": "16.8.1", "graphql-list-fields": "2.0.2", "graphql-relay": "0.10.0", "graphql-tag": "2.12.6", From b70c2d9027c428bb6882337c5e56c4a7c3cabdf8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 22 Sep 2023 01:23:36 +0000 Subject: [PATCH 05/33] chore(release): 6.4.0-alpha.2 [skip ci] # [6.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.1...6.4.0-alpha.2) (2023-09-22) ### Bug Fixes * Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index e3f679c6a0..0c126d3401 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.1...6.4.0-alpha.2) (2023-09-22) + + +### Bug Fixes + +* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) + # [6.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-alpha.1) (2023-09-20) ### Features diff --git a/package-lock.json b/package-lock.json index ec0c49e339..234f2c2152 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.1", + "version": "6.4.0-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.1", + "version": "6.4.0-alpha.2", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 7c35bd61a6..76ff7c786d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.1", + "version": "6.4.0-alpha.2", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 3d6d50e0afff18b95fb906914e2cebd3839b517a Mon Sep 17 00:00:00 2001 From: Marc Derhammer Date: Sat, 23 Sep 2023 16:43:34 -0400 Subject: [PATCH 06/33] fix: Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots (#8754) --- spec/ParseFile.spec.js | 68 ++++++++++++++++++++++++++++++++++++++ src/Routers/FilesRouter.js | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index f083c90ae4..d12c9e5d6f 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -1364,6 +1364,74 @@ describe('Parse.File testing', () => { ); }); + it('works with a period in the file name', async () => { + await reconfigureServer({ + fileUpload: { + enableForPublic: true, + fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], + }, + }); + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + + const values = ['file.png.html', 'file.txt.png.html', 'file.png.txt.html']; + + for (const value of values) { + await expectAsync( + request({ + method: 'POST', + headers: headers, + url: `http://localhost:8378/1/files/${value}`, + body: '\n', + }).catch(e => { + throw new Error(e.data.error); + }) + ).toBeRejectedWith( + new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`) + ); + } + }); + + it('works to stop invalid filenames', async () => { + await reconfigureServer({ + fileUpload: { + enableForPublic: true, + fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], + }, + }); + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + + const values = [ + '!invalid.png', + '.png', + '.html', + ' .html', + '.png.html', + '~invalid.png', + '-invalid.png', + ]; + + for (const value of values) { + await expectAsync( + request({ + method: 'POST', + headers: headers, + url: `http://localhost:8378/1/files/${value}`, + body: '\n', + }).catch(e => { + throw new Error(e.data.error); + }) + ).toBeRejectedWith( + new Parse.Error(Parse.Error.INVALID_FILE_NAME, `Filename contains invalid characters.`) + ); + } + }); + it('works with array', async () => { await reconfigureServer({ fileUpload: { diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index cbb59fdcdd..a063fecb95 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -155,7 +155,7 @@ export class FilesRouter { }; let extension = contentType; if (filename && filename.includes('.')) { - extension = filename.split('.')[1]; + extension = filename.substring(filename.lastIndexOf('.') + 1); } else if (contentType && contentType.includes('/')) { extension = contentType.split('/')[1]; } From 9b9c3a421453983d8618c83b4fe037da34cdbe78 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 23 Sep 2023 20:44:36 +0000 Subject: [PATCH 07/33] chore(release): 6.4.0-alpha.3 [skip ci] # [6.4.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.2...6.4.0-alpha.3) (2023-09-23) ### Bug Fixes * Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 0c126d3401..ca0b3b3b06 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.2...6.4.0-alpha.3) (2023-09-23) + + +### Bug Fixes + +* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) + # [6.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.1...6.4.0-alpha.2) (2023-09-22) diff --git a/package-lock.json b/package-lock.json index 234f2c2152..22acca122a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.2", + "version": "6.4.0-alpha.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.2", + "version": "6.4.0-alpha.3", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 76ff7c786d..8db6451f38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.2", + "version": "6.4.0-alpha.3", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 77bbfb3f186f5651c33ba152f04cff95128eaf2d Mon Sep 17 00:00:00 2001 From: Wes Date: Fri, 29 Sep 2023 13:17:48 -0700 Subject: [PATCH 08/33] feat: Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key (#8696) --- README.md | 14 +++-- spec/helper.js | 5 +- spec/rest.spec.js | 113 +++++++++++++++++++++++++++++++++++++ src/Options/Definitions.js | 2 +- src/Options/docs.js | 2 +- src/Options/index.js | 2 +- src/RestWrite.js | 33 ++++++++++- 7 files changed, 158 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0288d5f4ba..d061e8c200 100644 --- a/README.md +++ b/README.md @@ -358,12 +358,14 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo ## Access Scopes -| Scope | Internal data | Custom data | Restricted by CLP, ACL | Key | -|----------------|---------------|-------------|------------------------|---------------------| -| Internal | r/w | r/w | no | `maintenanceKey` | -| Master | -/- | r/w | no | `masterKey` | -| ReadOnlyMaster | -/- | r/- | no | `readOnlyMasterKey` | -| Session | -/- | r/w | yes | `sessionToken` | +| Scope | Internal data | Read-only data (1) | Custom data | Restricted by CLP, ACL | Key | +|----------------|---------------|-------------------------------|-------------|------------------------|---------------------| +| Internal | r/w | r/w | r/w | no | `maintenanceKey` | +| Master | -/- | r/- | r/w | no | `masterKey` | +| ReadOnlyMaster | -/- | r/- | r/- | no | `readOnlyMasterKey` | +| Session | -/- | r/- | r/w | yes | `sessionToken` | + +(1) `Parse.Object.createdAt`, `Parse.Object.updatedAt`. ## Email Verification and Password Reset diff --git a/spec/helper.js b/spec/helper.js index 445de26509..128a0401c5 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -103,6 +103,7 @@ const defaultConfiguration = { restAPIKey: 'rest', webhookKey: 'hook', masterKey: 'test', + maintenanceKey: 'testing', readOnlyMasterKey: 'read-only-test', fileKey: 'test', directAccess: true, @@ -250,8 +251,8 @@ afterEach(function (done) { }) .then(() => Parse.User.logOut()) .then( - () => {}, - () => {} + () => { }, + () => { } ) // swallow errors .then(() => { // Connection close events are not immediate on node 10+... wait a bit diff --git a/spec/rest.spec.js b/spec/rest.spec.js index 61a5c728e4..dadba596c4 100644 --- a/spec/rest.spec.js +++ b/spec/rest.spec.js @@ -136,6 +136,119 @@ describe('rest create', () => { }); }); + describe('with maintenance key', () => { + let req; + + async function getObject(id) { + const res = await request({ + headers: { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest' + }, + method: 'GET', + url: `http://localhost:8378/1/classes/TestObject/${id}` + }); + + return res.data; + } + + beforeEach(() => { + req = { + headers: { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + 'X-Parse-Maintenance-Key': 'testing' + }, + method: 'POST', + url: 'http://localhost:8378/1/classes/TestObject' + }; + }); + + it('allows createdAt', async () => { + const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; + req.body = { createdAt }; + + const res = await request(req); + expect(res.data.createdAt).toEqual(createdAt.iso); + }); + + it('allows createdAt and updatedAt', async () => { + const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; + const updatedAt = { __type: 'Date', iso: '2019-02-01T00:00:00.000Z' }; + req.body = { createdAt, updatedAt }; + + const res = await request(req); + + const obj = await getObject(res.data.objectId); + expect(obj.createdAt).toEqual(createdAt.iso); + expect(obj.updatedAt).toEqual(updatedAt.iso); + }); + + it('allows createdAt, updatedAt, and additional field', async () => { + const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; + const updatedAt = { __type: 'Date', iso: '2019-02-01T00:00:00.000Z' }; + req.body = { createdAt, updatedAt, testing: 123 }; + + const res = await request(req); + + const obj = await getObject(res.data.objectId); + expect(obj.createdAt).toEqual(createdAt.iso); + expect(obj.updatedAt).toEqual(updatedAt.iso); + expect(obj.testing).toEqual(123); + }); + + it('cannot set updatedAt dated before createdAt', async () => { + const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; + const updatedAt = { __type: 'Date', iso: '2018-12-01T00:00:00.000Z' }; + req.body = { createdAt, updatedAt }; + + try { + await request(req); + fail(); + } + catch (err) { + expect(err.data.code).toEqual(Parse.Error.VALIDATION_ERROR); + } + }); + + it('cannot set updatedAt without createdAt', async () => { + const updatedAt = { __type: 'Date', iso: '2018-12-01T00:00:00.000Z' }; + req.body = { updatedAt }; + + const res = await request(req); + + const obj = await getObject(res.data.objectId); + expect(obj.updatedAt).not.toEqual(updatedAt.iso); + }); + + it('handles bad types for createdAt and updatedAt', async () => { + const createdAt = 12345; + const updatedAt = true; + req.body = { createdAt, updatedAt }; + + try { + await request(req); + fail(); + } + catch (err) { + expect(err.data.code).toEqual(Parse.Error.INCORRECT_TYPE); + } + }); + + it('cannot set createdAt or updatedAt without maintenance key', async () => { + const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; + const updatedAt = { __type: 'Date', iso: '2019-02-01T00:00:00.000Z' }; + req.body = { createdAt, updatedAt }; + delete req.headers['X-Parse-Maintenance-Key']; + + const res = await request(req); + + expect(res.data.createdAt).not.toEqual(createdAt.iso); + expect(res.data.updatedAt).not.toEqual(updatedAt.iso); + }); + }); + it('handles array, object, date', done => { const now = new Date(); const obj = { diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 7a1e56bad0..f35300b287 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -317,7 +317,7 @@ module.exports.ParseServerOptions = { maintenanceKey: { env: 'PARSE_SERVER_MAINTENANCE_KEY', help: - '(Optional) The maintenance key is used for modifying internal fields of Parse Server.

\u26A0\uFE0F This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server.', + '(Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

\u26A0\uFE0F This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server.', required: true, }, maintenanceKeyIps: { diff --git a/src/Options/docs.js b/src/Options/docs.js index 09e6f5b3b4..cf672cc6cb 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -60,7 +60,7 @@ * @property {String} logLevel Sets the level for logs * @property {LogLevels} logLevels (Optional) Overrides the log levels used internally by Parse Server to log events. * @property {String} logsFolder Folder for the logs (defaults to './logs'); set to null to disable file based logging - * @property {String} maintenanceKey (Optional) The maintenance key is used for modifying internal fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. + * @property {String} maintenanceKey (Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. * @property {String[]} maintenanceKeyIps (Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key. * @property {String} masterKey Your Parse Master Key * @property {String[]} masterKeyIps (Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key. diff --git a/src/Options/index.js b/src/Options/index.js index d501b996dd..996512e36e 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -47,7 +47,7 @@ export interface ParseServerOptions { appId: string; /* Your Parse Master Key */ masterKey: string; - /* (Optional) The maintenance key is used for modifying internal fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. */ + /* (Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. */ maintenanceKey: string; /* URL to your parse server with http:// or https://. :ENV: PARSE_SERVER_URL */ diff --git a/src/RestWrite.js b/src/RestWrite.js index a469936fd8..1f640b4fd4 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -368,9 +368,36 @@ RestWrite.prototype.setRequiredFieldsIfNeeded = function () { }; // Add default fields - this.data.updatedAt = this.updatedAt; if (!this.query) { - this.data.createdAt = this.updatedAt; + // allow customizing createdAt and updatedAt when using maintenance key + if ( + this.auth.isMaintenance && + this.data.createdAt && + this.data.createdAt.__type === 'Date' + ) { + this.data.createdAt = this.data.createdAt.iso; + + if (this.data.updatedAt && this.data.updatedAt.__type === 'Date') { + const createdAt = new Date(this.data.createdAt); + const updatedAt = new Date(this.data.updatedAt.iso); + + if (updatedAt < createdAt) { + throw new Parse.Error( + Parse.Error.VALIDATION_ERROR, + 'updatedAt cannot occur before createdAt' + ); + } + + this.data.updatedAt = this.data.updatedAt.iso; + } + // if no updatedAt is provided, set it to createdAt to match default behavior + else { + this.data.updatedAt = this.data.createdAt; + } + } else { + this.data.updatedAt = this.updatedAt; + this.data.createdAt = this.updatedAt; + } // Only assign new objectId if we are creating new object if (!this.data.objectId) { @@ -382,6 +409,8 @@ RestWrite.prototype.setRequiredFieldsIfNeeded = function () { }); } } else if (schema) { + this.data.updatedAt = this.updatedAt; + Object.keys(this.data).forEach(fieldName => { setRequiredFieldIfNeeded(fieldName, false); }); From a2a98b16847c2ad0d29756286a6ed9b1f183a906 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 29 Sep 2023 20:18:59 +0000 Subject: [PATCH 09/33] chore(release): 6.4.0-alpha.4 [skip ci] # [6.4.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.3...6.4.0-alpha.4) (2023-09-29) ### Features * Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index ca0b3b3b06..b7aed4623a 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.3...6.4.0-alpha.4) (2023-09-29) + + +### Features + +* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) + # [6.4.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.2...6.4.0-alpha.3) (2023-09-23) diff --git a/package-lock.json b/package-lock.json index 22acca122a..b9fdf7769b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.3", + "version": "6.4.0-alpha.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.3", + "version": "6.4.0-alpha.4", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 8db6451f38..6f7d8cd6aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.3", + "version": "6.4.0-alpha.4", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 8d3117e0bcf07d6c9f8cb1343b5b9b6ded7d7cb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 13:29:46 +0200 Subject: [PATCH 10/33] refactor: Bump postcss from 8.4.20 to 8.4.31 (#8771) --- package-lock.json | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9fdf7769b..f733050b21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12211,10 +12211,16 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -16586,9 +16592,9 @@ } }, "node_modules/postcss": { - "version": "8.4.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", - "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -16598,10 +16604,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -29958,9 +29968,9 @@ "optional": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true }, "nanomatch": { @@ -33152,12 +33162,12 @@ "optional": true }, "postcss": { - "version": "8.4.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", - "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } From 7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3 Mon Sep 17 00:00:00 2001 From: Rikard Teodorsson <9367038+hej2010@users.noreply.github.com> Date: Sat, 14 Oct 2023 02:57:47 +0200 Subject: [PATCH 11/33] fix: Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` (#8765) --- spec/CloudCode.spec.js | 25 +++++++++++++++++++++++++ src/RestQuery.js | 8 +++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 37ab6a0c32..a1c8b48bfd 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -2510,6 +2510,31 @@ describe('beforeFind hooks', () => { expect(res2.get('pointerFieldArray')[0].get('aField')).toBe('aFieldValue'); expect(spy).toHaveBeenCalledTimes(2); }); + + it('should have access to context in include query in beforeFind hook', async () => { + let beforeFindTestObjectCalled = false; + let beforeFindTestObject2Called = false; + const obj1 = new Parse.Object('TestObject'); + const obj2 = new Parse.Object('TestObject2'); + obj2.set('aField', 'aFieldValue'); + await obj2.save(); + obj1.set('pointerField', obj2); + await obj1.save(); + Parse.Cloud.beforeFind('TestObject', req => { + expect(req.context).toBeDefined(); + expect(req.context.a).toEqual('a'); + beforeFindTestObjectCalled = true; + }); + Parse.Cloud.beforeFind('TestObject2', req => { + expect(req.context).toBeDefined(); + expect(req.context.a).toEqual('a'); + beforeFindTestObject2Called = true; + }); + const query = new Parse.Query('TestObject'); + await query.include('pointerField').find({ context: { a: 'a' } }); + expect(beforeFindTestObjectCalled).toBeTrue(); + expect(beforeFindTestObject2Called).toBeTrue(); + }); }); describe('afterFind hooks', () => { diff --git a/src/RestQuery.js b/src/RestQuery.js index 96a52ec17a..5af678bb96 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -478,6 +478,7 @@ _UnsafeRestQuery.prototype.replaceInQuery = async function () { className: inQueryValue.className, restWhere: inQueryValue.where, restOptions: additionalOptions, + context: this.context, }); return subquery.execute().then(response => { transformInQuery(inQueryObject, subquery.className, response.results); @@ -537,6 +538,7 @@ _UnsafeRestQuery.prototype.replaceNotInQuery = async function () { className: notInQueryValue.className, restWhere: notInQueryValue.where, restOptions: additionalOptions, + context: this.context, }); return subquery.execute().then(response => { @@ -609,6 +611,7 @@ _UnsafeRestQuery.prototype.replaceSelect = async function () { className: selectValue.query.className, restWhere: selectValue.query.where, restOptions: additionalOptions, + context: this.context, }); return subquery.execute().then(response => { @@ -671,6 +674,7 @@ _UnsafeRestQuery.prototype.replaceDontSelect = async function () { className: dontSelectValue.query.className, restWhere: dontSelectValue.query.where, restOptions: additionalOptions, + context: this.context, }); return subquery.execute().then(response => { @@ -860,6 +864,7 @@ _UnsafeRestQuery.prototype.handleInclude = function () { this.auth, this.response, this.include[0], + this.context, this.restOptions ); if (pathResponse.then) { @@ -946,7 +951,7 @@ _UnsafeRestQuery.prototype.handleAuthAdapters = async function () { // Adds included values to the response. // Path is a list of field names. // Returns a promise for an augmented response. -function includePath(config, auth, response, path, restOptions = {}) { +function includePath(config, auth, response, path, context, restOptions = {}) { var pointers = findPointers(response.results, path); if (pointers.length == 0) { return response; @@ -1026,6 +1031,7 @@ function includePath(config, auth, response, path, restOptions = {}) { className, restWhere: where, restOptions: includeRestOptions, + context: context, }); return query.execute({ op: 'get' }).then(results => { results.className = className; From 5462834240bee8e667d00ba18985d1b7da46b337 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 14 Oct 2023 00:58:51 +0000 Subject: [PATCH 12/33] chore(release): 6.4.0-alpha.5 [skip ci] # [6.4.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.4...6.4.0-alpha.5) (2023-10-14) ### Bug Fixes * Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index b7aed4623a..f24ff35127 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.4...6.4.0-alpha.5) (2023-10-14) + + +### Bug Fixes + +* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) + # [6.4.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.3...6.4.0-alpha.4) (2023-09-29) diff --git a/package-lock.json b/package-lock.json index f733050b21..4a9ba26c71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.4", + "version": "6.4.0-alpha.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.4", + "version": "6.4.0-alpha.5", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 6f7d8cd6aa..5c551e9ae8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.4", + "version": "6.4.0-alpha.5", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 93af48a8b4ca2ba19ed213af3dfd8ca2d786fafb Mon Sep 17 00:00:00 2001 From: Doug Drechsel Date: Wed, 18 Oct 2023 16:39:41 -0400 Subject: [PATCH 13/33] ci: Add ability to exclude tests via ID in `testExclusionList.json` (#8774) --- spec/.eslintrc.json | 1 + spec/helper.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/spec/.eslintrc.json b/spec/.eslintrc.json index 8f8bcfeddc..ff45304cd5 100644 --- a/spec/.eslintrc.json +++ b/spec/.eslintrc.json @@ -15,6 +15,7 @@ "equal": true, "expectAsync": true, "notEqual": true, + "it_id": true, "it_only_db": true, "it_only_mongodb_version": true, "it_only_postgres_version": true, diff --git a/spec/helper.js b/spec/helper.js index 128a0401c5..d393ef1d17 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -428,6 +428,29 @@ global.it_exclude_dbs = excluded => { } }; +let testExclusionList = []; +try { + // Fetch test exclusion list + testExclusionList = require('./testExclusionList.json'); + console.log(`Using test exclusion list with ${testExclusionList.length} entries`); +} catch(error) { + if(error.code !== 'MODULE_NOT_FOUND') { + throw error; + } +} + +// Disable test if its UUID is found in testExclusionList +global.it_id = (id, func) => { + if (testExclusionList.includes(id)) { + return xit; + } else { + if(func === undefined) + return it; + else + return func; + } +}; + global.it_only_db = db => { if ( process.env.PARSE_SERVER_TEST_DB === db || From 2d6b3d18499179e99be116f25c0850d3f449509c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 23:45:24 +0200 Subject: [PATCH 14/33] fix: Security bump @babel/traverse from 7.20.5 to 7.23.2 (#8777) --- package-lock.json | 248 +++++++++++++++++++++++----------------------- 1 file changed, 126 insertions(+), 122 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4a9ba26c71..b56c990833 100644 --- a/package-lock.json +++ b/package-lock.json @@ -227,11 +227,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -325,12 +326,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -376,9 +378,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } @@ -396,23 +398,23 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -520,28 +522,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -583,12 +585,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -596,9 +598,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1797,31 +1799,31 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1830,12 +1832,12 @@ } }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -20759,11 +20761,12 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -20829,12 +20832,13 @@ } }, "@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "requires": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -20870,9 +20874,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-explode-assignable-expression": { "version": "7.18.6", @@ -20884,20 +20888,20 @@ } }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -20978,22 +20982,22 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -21023,19 +21027,19 @@ } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-proposal-object-rest-spread": { "version": "7.10.0", @@ -21862,39 +21866,39 @@ } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, From 5dd3aa0d4886f06a806d7b883dcdf1ebb904b39e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 18 Oct 2023 21:46:43 +0000 Subject: [PATCH 15/33] chore(release): 6.4.0-alpha.6 [skip ci] # [6.4.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.5...6.4.0-alpha.6) (2023-10-18) ### Bug Fixes * Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index f24ff35127..980cebcd02 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.5...6.4.0-alpha.6) (2023-10-18) + + +### Bug Fixes + +* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) + # [6.4.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.4...6.4.0-alpha.5) (2023-10-14) diff --git a/package-lock.json b/package-lock.json index b56c990833..4e57b5d82a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.5", + "version": "6.4.0-alpha.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.5", + "version": "6.4.0-alpha.6", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 5c551e9ae8..456aafaef6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.5", + "version": "6.4.0-alpha.6", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From fd86278919556d3682e7e2c856dfccd5beffbfc0 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 21 Oct 2023 01:01:35 +0200 Subject: [PATCH 16/33] fix: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8781) --- spec/ParseFile.spec.js | 28 ++++++++++++++++++++++++++++ src/Routers/FilesRouter.js | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index eeab537008..b4fc72bdbd 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -1364,6 +1364,34 @@ describe('Parse.File testing', () => { ); }); + it('allows file without extension', async () => { + await reconfigureServer({ + fileUpload: { + enableForPublic: true, + fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], + }, + }); + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + + const values = ['filenamewithoutextension']; + + for (const value of values) { + await expectAsync( + request({ + method: 'POST', + headers: headers, + url: `http://localhost:8378/1/files/${value}`, + body: '\n', + }).catch(e => { + throw new Error(e.data.error); + }) + ).toBeResolved(); + } + }); + it('works with array', async () => { await reconfigureServer({ fileUpload: { diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index a5322b4c60..408dc81d8f 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -159,9 +159,9 @@ export class FilesRouter { } else if (contentType && contentType.includes('/')) { extension = contentType.split('/')[1]; } - extension = extension.split(' ').join(''); + extension = extension?.split(' ')?.join(''); - if (!isValidExtension(extension)) { + if (extension && !isValidExtension(extension)) { next( new Parse.Error( Parse.Error.FILE_SAVE_ERROR, From b0c012e835d573fbddf3c0efc27a6b139fe3f097 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 20 Oct 2023 23:02:48 +0000 Subject: [PATCH 17/33] chore(release): 6.3.1 [skip ci] ## [6.3.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.3.1) (2023-10-20) ### Bug Fixes * Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) ([#8781](https://github.com/parse-community/parse-server/issues/8781)) ([fd86278](https://github.com/parse-community/parse-server/commit/fd86278919556d3682e7e2c856dfccd5beffbfc0)) --- changelogs/CHANGELOG_release.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index b93450cc36..8d53c4e760 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,10 @@ +## [6.3.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.3.1) (2023-10-20) + + +### Bug Fixes + +* Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) ([#8781](https://github.com/parse-community/parse-server/issues/8781)) ([fd86278](https://github.com/parse-community/parse-server/commit/fd86278919556d3682e7e2c856dfccd5beffbfc0)) + # [6.3.0](https://github.com/parse-community/parse-server/compare/6.2.2...6.3.0) (2023-09-16) diff --git a/package-lock.json b/package-lock.json index 51cb4ac7a9..6584a1332c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.3.0", + "version": "6.3.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.3.0", + "version": "6.3.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index aeefd288c0..850f764a59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.3.0", + "version": "6.3.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From fe02d3e8aa875f362377cc877a65831b010b00a6 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 21 Oct 2023 01:03:02 +0200 Subject: [PATCH 18/33] refactor: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8779) --- spec/ParseFile.spec.js | 28 ++++++++++++++++++++++++++++ src/Routers/FilesRouter.js | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index d12c9e5d6f..e36929636b 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -1432,6 +1432,34 @@ describe('Parse.File testing', () => { } }); + it('allows file without extension', async () => { + await reconfigureServer({ + fileUpload: { + enableForPublic: true, + fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], + }, + }); + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + + const values = ['filenamewithoutextension']; + + for (const value of values) { + await expectAsync( + request({ + method: 'POST', + headers: headers, + url: `http://localhost:8378/1/files/${value}`, + body: '\n', + }).catch(e => { + throw new Error(e.data.error); + }) + ).toBeResolved(); + } + }); + it('works with array', async () => { await reconfigureServer({ fileUpload: { diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index a063fecb95..332cd75748 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -159,9 +159,9 @@ export class FilesRouter { } else if (contentType && contentType.includes('/')) { extension = contentType.split('/')[1]; } - extension = extension.split(' ').join(''); + extension = extension?.split(' ')?.join(''); - if (!isValidExtension(extension)) { + if (extension && !isValidExtension(extension)) { next( new Parse.Error( Parse.Error.FILE_SAVE_ERROR, From ea57a7706d75d21754d04985a580d040efe45939 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 21 Oct 2023 01:03:31 +0200 Subject: [PATCH 19/33] refactor: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8780) --- spec/ParseFile.spec.js | 28 ++++++++++++++++++++++++++++ src/Routers/FilesRouter.js | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index f083c90ae4..5f5ab43c54 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -1364,6 +1364,34 @@ describe('Parse.File testing', () => { ); }); + it('allows file without extension', async () => { + await reconfigureServer({ + fileUpload: { + enableForPublic: true, + fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], + }, + }); + const headers = { + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + + const values = ['filenamewithoutextension']; + + for (const value of values) { + await expectAsync( + request({ + method: 'POST', + headers: headers, + url: `http://localhost:8378/1/files/${value}`, + body: '\n', + }).catch(e => { + throw new Error(e.data.error); + }) + ).toBeResolved(); + } + }); + it('works with array', async () => { await reconfigureServer({ fileUpload: { diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index cbb59fdcdd..165e0924ce 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -159,9 +159,9 @@ export class FilesRouter { } else if (contentType && contentType.includes('/')) { extension = contentType.split('/')[1]; } - extension = extension.split(' ').join(''); + extension = extension?.split(' ')?.join(''); - if (!isValidExtension(extension)) { + if (extension && !isValidExtension(extension)) { next( new Parse.Error( Parse.Error.FILE_SAVE_ERROR, From f630a45aa5e87bc73a81fded061400c199b71a29 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 25 Oct 2023 19:13:27 +0200 Subject: [PATCH 20/33] feat: Add `$setOnInsert` operator to `Parse.Server.database.update` (#8791) --- spec/MongoStorageAdapter.spec.js | 39 ++++++++++++++++++++ src/Adapters/Storage/Mongo/MongoTransform.js | 7 ++++ src/Controllers/DatabaseController.js | 5 ++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index 1b5cc0c5e9..29a97b2ddb 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -254,6 +254,45 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue(); }); + it('upserts with $setOnInsert', async () => { + const uuid = require('uuid'); + const uuid1 = uuid.v4(); + const uuid2 = uuid.v4(); + const query = { + x: 1, + }; + const update = { + objectId: { + __op: 'SetOnInsert', + amount: uuid1, + }, + x: 1, + count: { + __op: 'Increment', + amount: 1, + }, + }; + await Parse.Server.database.update( + 'MyClass', + query, + update, + { upsert: true }, + ); + update.objectId.amount = uuid2; + await Parse.Server.database.update( + 'MyClass', + query, + update, + { upsert: true }, + ); + const q = new Parse.Query('MyClass'); + const docs = await q.find(); + expect(docs.length).toBe(1); + expect(docs[0].id).toBe(uuid1); + expect(docs[0].get('x')).toBe(1); + expect(docs[0].get('count')).toBe(2); + }); + it('handles updating a single object with array, object date', done => { const adapter = new MongoStorageAdapter({ uri: databaseURI }); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 6f6811cec3..7f66fb32fb 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -986,6 +986,13 @@ function transformUpdateOperator({ __op, amount, objects }, flatten) { return { __op: '$inc', arg: amount }; } + case 'SetOnInsert': + if (flatten) { + return amount; + } else { + return { __op: '$setOnInsert', arg: amount }; + } + case 'Add': case 'AddUnique': if (!(objects instanceof Array)) { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index f9c782db87..defb7976c4 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -279,6 +279,9 @@ const flattenUpdateOperatorsForCreate = object => { } object[key] = object[key].amount; break; + case 'SetOnInsert': + object[key] = object[key].amount; + break; case 'Add': if (!(object[key].objects instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array'); @@ -1817,7 +1820,7 @@ class DatabaseController { keyUpdate && typeof keyUpdate === 'object' && keyUpdate.__op && - ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1 + ['Add', 'AddUnique', 'Remove', 'Increment', 'SetOnInsert'].indexOf(keyUpdate.__op) > -1 ) { // only valid ops that produce an actionable result // the op may have happened on a keypath From 9e0094980fd2653492e7eed1d20a90e9f94c0390 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 25 Oct 2023 17:14:37 +0000 Subject: [PATCH 21/33] chore(release): 6.4.0-alpha.7 [skip ci] # [6.4.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.6...6.4.0-alpha.7) (2023-10-25) ### Features * Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 980cebcd02..a4d655f122 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.6...6.4.0-alpha.7) (2023-10-25) + + +### Features + +* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) + # [6.4.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.5...6.4.0-alpha.6) (2023-10-18) diff --git a/package-lock.json b/package-lock.json index 4e57b5d82a..57f9dde81e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.6", + "version": "6.4.0-alpha.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.6", + "version": "6.4.0-alpha.7", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 456aafaef6..1248432259 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.6", + "version": "6.4.0-alpha.7", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 80b987d00d8eda89f1ee521103c4737b64c66cc1 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:32:58 +0200 Subject: [PATCH 22/33] test: Improve test for `$setOnInsert` (#8793) --- spec/MongoStorageAdapter.spec.js | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index 29a97b2ddb..25a6ae5639 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -258,6 +258,19 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { const uuid = require('uuid'); const uuid1 = uuid.v4(); const uuid2 = uuid.v4(); + const schema = { + className: 'MyClass', + fields: { + x: { type: 'Number' }, + count: { type: 'Number' }, + }, + classLevelPermissions: {}, + }; + + const myClassSchema = new Parse.Schema(schema.className); + myClassSchema.setCLP(schema.classLevelPermissions); + await myClassSchema.save(); + const query = { x: 1, }; @@ -266,7 +279,6 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { __op: 'SetOnInsert', amount: uuid1, }, - x: 1, count: { __op: 'Increment', amount: 1, @@ -285,12 +297,16 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { update, { upsert: true }, ); - const q = new Parse.Query('MyClass'); - const docs = await q.find(); - expect(docs.length).toBe(1); - expect(docs[0].id).toBe(uuid1); - expect(docs[0].get('x')).toBe(1); - expect(docs[0].get('count')).toBe(2); + + const res = await Parse.Server.database.find( + schema.className, + {}, + {}, + ); + expect(res.length).toBe(1); + expect(res[0].objectId).toBe(uuid1); + expect(res[0].count).toBe(2); + expect(res[0].x).toBe(1); }); it('handles updating a single object with array, object date', done => { From 09fbeebba8870e7cf371fb84371a254c7b368620 Mon Sep 17 00:00:00 2001 From: Mattia Faraci <82614156+mattia1208@users.noreply.github.com> Date: Mon, 13 Nov 2023 23:32:47 +0100 Subject: [PATCH 23/33] feat: Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` (#8805) --- spec/DatabaseController.spec.js | 254 ++++++++++++++++++++++++++ src/Controllers/DatabaseController.js | 50 +++-- src/Options/Definitions.js | 21 +++ src/Options/docs.js | 3 + src/Options/index.js | 9 + 5 files changed, 323 insertions(+), 14 deletions(-) diff --git a/spec/DatabaseController.spec.js b/spec/DatabaseController.spec.js index 98103ce6e4..e1b50a5a52 100644 --- a/spec/DatabaseController.spec.js +++ b/spec/DatabaseController.spec.js @@ -1,3 +1,4 @@ +const Config = require('../lib/Config'); const DatabaseController = require('../lib/Controllers/DatabaseController.js'); const validateQuery = DatabaseController._validateQuery; @@ -361,6 +362,259 @@ describe('DatabaseController', function () { done(); }); }); + + describe('enableCollationCaseComparison', () => { + const dummyStorageAdapter = { + find: () => Promise.resolve([]), + watch: () => Promise.resolve(), + getAllClasses: () => Promise.resolve([]), + }; + + beforeEach(() => { + Config.get(Parse.applicationId).schemaCache.clear(); + }); + + it('should force caseInsensitive to false with enableCollationCaseComparison option', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, { + enableCollationCaseComparison: true, + }); + const spy = spyOn(dummyStorageAdapter, 'find'); + spy.and.callThrough(); + await databaseController.find('SomeClass', {}, { caseInsensitive: true }); + expect(spy.calls.all()[0].args[3].caseInsensitive).toEqual(false); + }); + + it('should support caseInsensitive without enableCollationCaseComparison option', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, {}); + const spy = spyOn(dummyStorageAdapter, 'find'); + spy.and.callThrough(); + await databaseController.find('_User', {}, { caseInsensitive: true }); + expect(spy.calls.all()[0].args[3].caseInsensitive).toEqual(true); + }); + + it_only_db('mongo')( + 'should create insensitive indexes without enableCollationCaseComparison', + async () => { + await reconfigureServer({ + databaseURI: 'mongodb://localhost:27017/enableCollationCaseComparisonFalse', + databaseAdapter: undefined, + }); + const user = new Parse.User(); + await user.save({ + username: 'example', + password: 'password', + email: 'example@example.com', + }); + const schemas = await Parse.Schema.all(); + const UserSchema = schemas.find(({ className }) => className === '_User'); + expect(UserSchema.indexes).toEqual({ + _id_: { _id: 1 }, + username_1: { username: 1 }, + case_insensitive_username: { username: 1 }, + case_insensitive_email: { email: 1 }, + email_1: { email: 1 }, + }); + } + ); + + it_only_db('mongo')( + 'should not create insensitive indexes with enableCollationCaseComparison', + async () => { + await reconfigureServer({ + enableCollationCaseComparison: true, + databaseURI: 'mongodb://localhost:27017/enableCollationCaseComparisonTrue', + databaseAdapter: undefined, + }); + const user = new Parse.User(); + await user.save({ + username: 'example', + password: 'password', + email: 'example@example.com', + }); + const schemas = await Parse.Schema.all(); + const UserSchema = schemas.find(({ className }) => className === '_User'); + expect(UserSchema.indexes).toEqual({ + _id_: { _id: 1 }, + username_1: { username: 1 }, + email_1: { email: 1 }, + }); + } + ); + }); + + describe('convertEmailToLowercase', () => { + const dummyStorageAdapter = { + createObject: () => Promise.resolve({ ops: [{}] }), + findOneAndUpdate: () => Promise.resolve({}), + watch: () => Promise.resolve(), + getAllClasses: () => + Promise.resolve([ + { + className: '_User', + fields: { email: 'String' }, + indexes: {}, + classLevelPermissions: { protectedFields: {} }, + }, + ]), + }; + const dates = { + createdAt: { iso: undefined, __type: 'Date' }, + updatedAt: { iso: undefined, __type: 'Date' }, + }; + + it('should not transform email to lower case without convertEmailToLowercase option on create', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, {}); + const spy = spyOn(dummyStorageAdapter, 'createObject'); + spy.and.callThrough(); + await databaseController.create('_User', { + email: 'EXAMPLE@EXAMPLE.COM', + }); + expect(spy.calls.all()[0].args[2]).toEqual({ + email: 'EXAMPLE@EXAMPLE.COM', + ...dates, + }); + }); + + it('should transform email to lower case with convertEmailToLowercase option on create', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, { + convertEmailToLowercase: true, + }); + const spy = spyOn(dummyStorageAdapter, 'createObject'); + spy.and.callThrough(); + await databaseController.create('_User', { + email: 'EXAMPLE@EXAMPLE.COM', + }); + expect(spy.calls.all()[0].args[2]).toEqual({ + email: 'example@example.com', + ...dates, + }); + }); + + it('should not transform email to lower case without convertEmailToLowercase option on update', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, {}); + const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); + spy.and.callThrough(); + await databaseController.update('_User', { id: 'example' }, { email: 'EXAMPLE@EXAMPLE.COM' }); + expect(spy.calls.all()[0].args[3]).toEqual({ + email: 'EXAMPLE@EXAMPLE.COM', + }); + }); + + it('should transform email to lower case with convertEmailToLowercase option on update', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, { + convertEmailToLowercase: true, + }); + const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); + spy.and.callThrough(); + await databaseController.update('_User', { id: 'example' }, { email: 'EXAMPLE@EXAMPLE.COM' }); + expect(spy.calls.all()[0].args[3]).toEqual({ + email: 'example@example.com', + }); + }); + + it('should not find a case insensitive user by email with convertEmailToLowercase', async () => { + await reconfigureServer({ convertEmailToLowercase: true }); + const user = new Parse.User(); + await user.save({ username: 'EXAMPLE', email: 'EXAMPLE@EXAMPLE.COM', password: 'password' }); + + const query = new Parse.Query(Parse.User); + query.equalTo('email', 'EXAMPLE@EXAMPLE.COM'); + const result = await query.find({ useMasterKey: true }); + expect(result.length).toEqual(0); + + const query2 = new Parse.Query(Parse.User); + query2.equalTo('email', 'example@example.com'); + const result2 = await query2.find({ useMasterKey: true }); + expect(result2.length).toEqual(1); + }); + }); + + describe('convertUsernameToLowercase', () => { + const dummyStorageAdapter = { + createObject: () => Promise.resolve({ ops: [{}] }), + findOneAndUpdate: () => Promise.resolve({}), + watch: () => Promise.resolve(), + getAllClasses: () => + Promise.resolve([ + { + className: '_User', + fields: { username: 'String' }, + indexes: {}, + classLevelPermissions: { protectedFields: {} }, + }, + ]), + }; + const dates = { + createdAt: { iso: undefined, __type: 'Date' }, + updatedAt: { iso: undefined, __type: 'Date' }, + }; + + it('should not transform username to lower case without convertUsernameToLowercase option on create', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, {}); + const spy = spyOn(dummyStorageAdapter, 'createObject'); + spy.and.callThrough(); + await databaseController.create('_User', { + username: 'EXAMPLE', + }); + expect(spy.calls.all()[0].args[2]).toEqual({ + username: 'EXAMPLE', + ...dates, + }); + }); + + it('should transform username to lower case with convertUsernameToLowercase option on create', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, { + convertUsernameToLowercase: true, + }); + const spy = spyOn(dummyStorageAdapter, 'createObject'); + spy.and.callThrough(); + await databaseController.create('_User', { + username: 'EXAMPLE', + }); + expect(spy.calls.all()[0].args[2]).toEqual({ + username: 'example', + ...dates, + }); + }); + + it('should not transform username to lower case without convertUsernameToLowercase option on update', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, {}); + const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); + spy.and.callThrough(); + await databaseController.update('_User', { id: 'example' }, { username: 'EXAMPLE' }); + expect(spy.calls.all()[0].args[3]).toEqual({ + username: 'EXAMPLE', + }); + }); + + it('should transform username to lower case with convertUsernameToLowercase option on update', async () => { + const databaseController = new DatabaseController(dummyStorageAdapter, { + convertUsernameToLowercase: true, + }); + const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); + spy.and.callThrough(); + await databaseController.update('_User', { id: 'example' }, { username: 'EXAMPLE' }); + expect(spy.calls.all()[0].args[3]).toEqual({ + username: 'example', + }); + }); + + it('should not find a case insensitive user by username with convertUsernameToLowercase', async () => { + await reconfigureServer({ convertUsernameToLowercase: true }); + const user = new Parse.User(); + await user.save({ username: 'EXAMPLE', password: 'password' }); + + const query = new Parse.Query(Parse.User); + query.equalTo('username', 'EXAMPLE'); + const result = await query.find({ useMasterKey: true }); + expect(result.length).toEqual(0); + + const query2 = new Parse.Query(Parse.User); + query2.equalTo('username', 'example'); + const result2 = await query2.find({ useMasterKey: true }); + expect(result2.length).toEqual(1); + }); + }); }); function buildCLP(pointerNames) { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index defb7976c4..5975e94053 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -368,6 +368,22 @@ const relationSchema = { fields: { relatedId: { type: 'String' }, owningId: { type: 'String' } }, }; +const convertEmailToLowercase = (object, className, options) => { + if (className === '_User' && options.convertEmailToLowercase) { + if (typeof object['email'] === 'string') { + object['email'] = object['email'].toLowerCase(); + } + } +}; + +const convertUsernameToLowercase = (object, className, options) => { + if (className === '_User' && options.convertUsernameToLowercase) { + if (typeof object['username'] === 'string') { + object['username'] = object['username'].toLowerCase(); + } + } +}; + class DatabaseController { adapter: StorageAdapter; schemaCache: any; @@ -573,6 +589,8 @@ class DatabaseController { } } update = transformObjectACL(update); + convertEmailToLowercase(update, className, this.options); + convertUsernameToLowercase(update, className, this.options); transformAuthData(className, update, schema); if (validateOnly) { return this.adapter.find(className, schema, query, {}).then(result => { @@ -822,6 +840,8 @@ class DatabaseController { const originalObject = object; object = transformObjectACL(object); + convertEmailToLowercase(object, className, this.options); + convertUsernameToLowercase(object, className, this.options); object.createdAt = { iso: object.createdAt, __type: 'Date' }; object.updatedAt = { iso: object.updatedAt, __type: 'Date' }; @@ -1215,7 +1235,7 @@ class DatabaseController { keys, readPreference, hint, - caseInsensitive, + caseInsensitive: this.options.enableCollationCaseComparison ? false : caseInsensitive, explain, }; Object.keys(sort).forEach(fieldName => { @@ -1719,25 +1739,27 @@ class DatabaseController { throw error; }); - await this.adapter - .ensureIndex('_User', requiredUserFields, ['username'], 'case_insensitive_username', true) - .catch(error => { - logger.warn('Unable to create case insensitive username index: ', error); - throw error; - }); + if (!this.options.enableCollationCaseComparison) { + await this.adapter + .ensureIndex('_User', requiredUserFields, ['username'], 'case_insensitive_username', true) + .catch(error => { + logger.warn('Unable to create case insensitive username index: ', error); + throw error; + }); + + await this.adapter + .ensureIndex('_User', requiredUserFields, ['email'], 'case_insensitive_email', true) + .catch(error => { + logger.warn('Unable to create case insensitive email index: ', error); + throw error; + }); + } await this.adapter.ensureUniqueness('_User', requiredUserFields, ['email']).catch(error => { logger.warn('Unable to ensure uniqueness for user email addresses: ', error); throw error; }); - await this.adapter - .ensureIndex('_User', requiredUserFields, ['email'], 'case_insensitive_email', true) - .catch(error => { - logger.warn('Unable to create case insensitive email index: ', error); - throw error; - }); - await this.adapter.ensureUniqueness('_Role', requiredRoleFields, ['name']).catch(error => { logger.warn('Unable to ensure uniqueness for role name: ', error); throw error; diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index f35300b287..c37e6adfc3 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -139,6 +139,20 @@ module.exports.ParseServerOptions = { help: 'A collection prefix for the classes', default: '', }, + convertEmailToLowercase: { + env: 'PARSE_SERVER_CONVERT_EMAIL_TO_LOWERCASE', + help: + 'Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`.', + action: parsers.booleanParser, + default: false, + }, + convertUsernameToLowercase: { + env: 'PARSE_SERVER_CONVERT_USERNAME_TO_LOWERCASE', + help: + 'Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`.', + action: parsers.booleanParser, + default: false, + }, customPages: { env: 'PARSE_SERVER_CUSTOM_PAGES', help: 'custom pages for password validation and reset', @@ -203,6 +217,13 @@ module.exports.ParseServerOptions = { action: parsers.booleanParser, default: true, }, + enableCollationCaseComparison: { + env: 'PARSE_SERVER_ENABLE_COLLATION_CASE_COMPARISON', + help: + 'Optional. If set to `true`, the collation rule of case comparison for queries and indexes is enabled. Enable this option to run Parse Server with MongoDB Atlas Serverless or AWS Amazon DocumentDB. If `false`, the collation rule of case comparison is disabled. Default is `false`.', + action: parsers.booleanParser, + default: false, + }, enableExpressErrorHandler: { env: 'PARSE_SERVER_ENABLE_EXPRESS_ERROR_HANDLER', help: 'Enables the default express error handler for all errors', diff --git a/src/Options/docs.js b/src/Options/docs.js index cf672cc6cb..cef358ad63 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -28,6 +28,8 @@ * @property {String} cloud Full path to your cloud code main.js * @property {Number|Boolean} cluster Run with cluster, optionally set the number of processes default to os.cpus().length * @property {String} collectionPrefix A collection prefix for the classes + * @property {Boolean} convertEmailToLowercase Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`. + * @property {Boolean} convertUsernameToLowercase Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`. * @property {CustomPagesOptions} customPages custom pages for password validation and reset * @property {Adapter} databaseAdapter Adapter module for the database; any options that are not explicitly described here are passed directly to the database client. * @property {DatabaseOptions} databaseOptions Options to pass to the database client @@ -39,6 +41,7 @@ * @property {Boolean} emailVerifyTokenReuseIfValid Set to `true` if a email verification token should be reused in case another token is requested but there is a token that is still valid, i.e. has not expired. This avoids the often observed issue that a user requests multiple emails and does not know which link contains a valid token because each newly generated token would invalidate the previous token.

Default is `false`.
Requires option `verifyUserEmails: true`. * @property {Number} emailVerifyTokenValidityDuration Set the validity duration of the email verification token in seconds after which the token expires. The token is used in the link that is set in the email. After the token expires, the link becomes invalid and a new link has to be sent. If the option is not set or set to `undefined`, then the token never expires.

For example, to expire the token after 2 hours, set a value of 7200 seconds (= 60 seconds * 60 minutes * 2 hours).

Default is `undefined`.
Requires option `verifyUserEmails: true`. * @property {Boolean} enableAnonymousUsers Enable (or disable) anonymous users, defaults to true + * @property {Boolean} enableCollationCaseComparison Optional. If set to `true`, the collation rule of case comparison for queries and indexes is enabled. Enable this option to run Parse Server with MongoDB Atlas Serverless or AWS Amazon DocumentDB. If `false`, the collation rule of case comparison is disabled. Default is `false`. * @property {Boolean} enableExpressErrorHandler Enables the default express error handler for all errors * @property {Boolean} encodeParseObjectInCloudFunction If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

ℹ️ The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`. * @property {String} encryptionKey Key for encrypting your files diff --git a/src/Options/index.js b/src/Options/index.js index 996512e36e..9af83ecd82 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -103,6 +103,15 @@ export interface ParseServerOptions { databaseOptions: ?DatabaseOptions; /* Adapter module for the database; any options that are not explicitly described here are passed directly to the database client. */ databaseAdapter: ?Adapter; + /* Optional. If set to `true`, the collation rule of case comparison for queries and indexes is enabled. Enable this option to run Parse Server with MongoDB Atlas Serverless or AWS Amazon DocumentDB. If `false`, the collation rule of case comparison is disabled. Default is `false`. + :DEFAULT: false */ + enableCollationCaseComparison: ?boolean; + /* Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`. + :DEFAULT: false */ + convertEmailToLowercase: ?boolean; + /* Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`. + :DEFAULT: false */ + convertUsernameToLowercase: ?boolean; /* Full path to your cloud code main.js */ cloud: ?string; /* A collection prefix for the classes From 4b3ce20300b05b015b48efeb82d693200159911f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 13 Nov 2023 22:33:43 +0000 Subject: [PATCH 24/33] chore(release): 6.4.0-alpha.8 [skip ci] # [6.4.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.7...6.4.0-alpha.8) (2023-11-13) ### Features * Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index a4d655f122..5430432163 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.4.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.7...6.4.0-alpha.8) (2023-11-13) + + +### Features + +* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) + # [6.4.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.6...6.4.0-alpha.7) (2023-10-25) diff --git a/package-lock.json b/package-lock.json index 57f9dde81e..cfa865ab08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.7", + "version": "6.4.0-alpha.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.7", + "version": "6.4.0-alpha.8", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 1248432259..970d630cfa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.7", + "version": "6.4.0-alpha.8", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From c6355cda73c204e1a29314f6085d00d5bc36c61a Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:58:24 +0100 Subject: [PATCH 25/33] release From 5b1bb598e46dfd07b732cb1769f3e0b6a9a046cc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Nov 2023 15:26:18 +0000 Subject: [PATCH 26/33] chore(release): 6.4.0 [skip ci] # [6.4.0](https://github.com/parse-community/parse-server/compare/6.3.1...6.4.0) (2023-11-16) ### Bug Fixes * Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) * Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) * Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) * Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) ### Features * Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) * Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) * Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) ### Performance Improvements * Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) --- changelogs/CHANGELOG_release.md | 20 ++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index 8d53c4e760..eaf5301ccc 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,23 @@ +# [6.4.0](https://github.com/parse-community/parse-server/compare/6.3.1...6.4.0) (2023-11-16) + + +### Bug Fixes + +* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) +* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) +* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) +* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) + +### Features + +* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) +* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) +* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) + +### Performance Improvements + +* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) + ## [6.3.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.3.1) (2023-10-20) diff --git a/package-lock.json b/package-lock.json index 5e831afe3e..1a390a4415 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-beta.1", + "version": "6.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-beta.1", + "version": "6.4.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 4a7bb746dd..250ec29bb5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-beta.1", + "version": "6.4.0", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 42e2e1295629b511453002a6a37c0fe64f87ec07 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:43:24 +0100 Subject: [PATCH 27/33] release From 988ecdac54c8f756e5e1f68eb522012a0adf4c89 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Nov 2023 15:57:46 +0000 Subject: [PATCH 28/33] chore(release): 6.5.0-beta.1 [skip ci] # [6.5.0-beta.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-beta.1) (2023-11-16) ### Bug Fixes * Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) * Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) * Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) * Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) ### Features * Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) * Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) * Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) * Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) --- changelogs/CHANGELOG_beta.md | 17 +++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_beta.md b/changelogs/CHANGELOG_beta.md index 9a671aaab5..dd80a35e3e 100644 --- a/changelogs/CHANGELOG_beta.md +++ b/changelogs/CHANGELOG_beta.md @@ -1,3 +1,20 @@ +# [6.5.0-beta.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-beta.1) (2023-11-16) + + +### Bug Fixes + +* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) +* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) +* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) +* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) + +### Features + +* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) +* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) +* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) +* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) + # [6.4.0-beta.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-beta.1) (2023-09-16) diff --git a/package-lock.json b/package-lock.json index cfa865ab08..0fb61dd020 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.4.0-alpha.8", + "version": "6.5.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.4.0-alpha.8", + "version": "6.5.0-beta.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 970d630cfa..26119380ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.4.0-alpha.8", + "version": "6.5.0-beta.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 6ef1986c03a1d84b7e11c05851e5bf9688d88740 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 18 Nov 2023 14:53:21 +0100 Subject: [PATCH 29/33] feat: Upgrade Parse Server Push Adapter to 5.0.2 (#8813) --- package-lock.json | 161 +++++++++++----------------------------------- package.json | 2 +- 2 files changed, 37 insertions(+), 126 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0fb61dd020..41e4ecd8ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@graphql-tools/utils": "8.12.0", "@graphql-yoga/node": "2.6.0", "@parse/fs-files-adapter": "1.2.2", - "@parse/push-adapter": "4.2.0", + "@parse/push-adapter": "5.0.2", "bcryptjs": "2.4.3", "body-parser": "1.20.2", "commander": "10.0.1", @@ -2733,9 +2733,9 @@ "integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g==" }, "node_modules/@parse/node-apn": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.2.1.tgz", - "integrity": "sha512-dwVCDv+G9YV01Ad1XslWQImnmfFDSnaNwxI4l+vuCjL+DbjsCl6DuV4nMqZpEZOpViAY0pGCRHBKUygsf+aAGg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-6.0.1.tgz", + "integrity": "sha512-QQxqEN/zbtEkSgj41oX/tQUavML+G+JHeQi2YVlgZlponnwIxA3fb5tEbXPm+fdR6rL1pi2/z2PcOwINOyx2eA==", "dependencies": { "debug": "4.3.3", "jsonwebtoken": "9.0.0", @@ -2743,7 +2743,7 @@ "verror": "1.10.1" }, "engines": { - "node": ">= 12" + "node": ">= 14" } }, "node_modules/@parse/node-apn/node_modules/debug": { @@ -2784,91 +2784,36 @@ } }, "node_modules/@parse/push-adapter": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-4.2.0.tgz", - "integrity": "sha512-M6D9qk4KE9bJ2lMufTvgGmKOvsbj20lFhzg0kQRmHU10ootKt4XcL+QJRSTu/BmlRbIVZMGQEZ61UyUumWTOiQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-5.0.2.tgz", + "integrity": "sha512-0nVBGj8p8cYGjoMdkVAlsa/UlB1Z4W6Ch7MEVcEfnyCmJBw6bvHwB1VVWoclcRqi3phsu3SizR5zVvB/Cx8I/g==", "dependencies": { - "@parse/node-apn": "5.2.1", + "@parse/node-apn": "6.0.1", "@parse/node-gcm": "1.0.2", "npmlog": "4.1.2", - "parse": "3.4.0" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@parse/push-adapter/node_modules/@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@parse/push-adapter/node_modules/@babel/runtime-corejs3": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz", - "integrity": "sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==", - "dependencies": { - "core-js-pure": "^3.15.0", - "regenerator-runtime": "^0.13.4" + "parse": "4.2.0" }, "engines": { - "node": ">=6.9.0" + "node": ">= 14" } }, - "node_modules/@parse/push-adapter/node_modules/idb-keyval": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-5.0.6.tgz", - "integrity": "sha512-6lJuVbwyo82mKSH6Wq2eHkt9LcbwHAelMIcMe0tP4p20Pod7tTxq9zf0ge2n/YDfMOpDryerfmmYyuQiaFaKOg==" - }, "node_modules/@parse/push-adapter/node_modules/parse": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.0.tgz", - "integrity": "sha512-FMZLxPW6PvrBgxkXc9AmnYsFKvPwiS4G2n9OI4mdfiSoNzIVLc+bXzlUdJ+I7hiqHsBTP0BrdQczw2/cnVkJ6w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/parse/-/parse-4.2.0.tgz", + "integrity": "sha512-K8bWs0wM2qRhkSr6N16j8OvsF6Uallrynqng9e+tzR3RdKuB09vaJh48qrf9MbiJ1Ya4JZI7AfEHYF+ywEKs7Q==", "dependencies": { - "@babel/runtime": "7.15.4", - "@babel/runtime-corejs3": "7.14.7", - "idb-keyval": "5.0.6", + "@babel/runtime-corejs3": "7.21.0", + "idb-keyval": "6.2.0", "react-native-crypto-js": "1.0.0", - "uuid": "3.4.0", - "ws": "7.5.1", + "uuid": "9.0.0", + "ws": "8.13.0", "xmlhttprequest": "1.8.0" }, - "optionalDependencies": { - "crypto-js": "4.1.1" - } - }, - "node_modules/@parse/push-adapter/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/@parse/push-adapter/node_modules/ws": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", - "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==", "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "node": ">=14.21.0 <17 || >=18 <20" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "optionalDependencies": { + "crypto-js": "4.1.1" } }, "node_modules/@redis/bloom": { @@ -22566,9 +22511,9 @@ "integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g==" }, "@parse/node-apn": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.2.1.tgz", - "integrity": "sha512-dwVCDv+G9YV01Ad1XslWQImnmfFDSnaNwxI4l+vuCjL+DbjsCl6DuV4nMqZpEZOpViAY0pGCRHBKUygsf+aAGg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-6.0.1.tgz", + "integrity": "sha512-QQxqEN/zbtEkSgj41oX/tQUavML+G+JHeQi2YVlgZlponnwIxA3fb5tEbXPm+fdR6rL1pi2/z2PcOwINOyx2eA==", "requires": { "debug": "4.3.3", "jsonwebtoken": "9.0.0", @@ -22607,63 +22552,29 @@ } }, "@parse/push-adapter": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-4.2.0.tgz", - "integrity": "sha512-M6D9qk4KE9bJ2lMufTvgGmKOvsbj20lFhzg0kQRmHU10ootKt4XcL+QJRSTu/BmlRbIVZMGQEZ61UyUumWTOiQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-5.0.2.tgz", + "integrity": "sha512-0nVBGj8p8cYGjoMdkVAlsa/UlB1Z4W6Ch7MEVcEfnyCmJBw6bvHwB1VVWoclcRqi3phsu3SizR5zVvB/Cx8I/g==", "requires": { - "@parse/node-apn": "5.2.1", + "@parse/node-apn": "6.0.1", "@parse/node-gcm": "1.0.2", "npmlog": "4.1.2", - "parse": "3.4.0" + "parse": "4.2.0" }, "dependencies": { - "@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/runtime-corejs3": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz", - "integrity": "sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==", - "requires": { - "core-js-pure": "^3.15.0", - "regenerator-runtime": "^0.13.4" - } - }, - "idb-keyval": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-5.0.6.tgz", - "integrity": "sha512-6lJuVbwyo82mKSH6Wq2eHkt9LcbwHAelMIcMe0tP4p20Pod7tTxq9zf0ge2n/YDfMOpDryerfmmYyuQiaFaKOg==" - }, "parse": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.0.tgz", - "integrity": "sha512-FMZLxPW6PvrBgxkXc9AmnYsFKvPwiS4G2n9OI4mdfiSoNzIVLc+bXzlUdJ+I7hiqHsBTP0BrdQczw2/cnVkJ6w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/parse/-/parse-4.2.0.tgz", + "integrity": "sha512-K8bWs0wM2qRhkSr6N16j8OvsF6Uallrynqng9e+tzR3RdKuB09vaJh48qrf9MbiJ1Ya4JZI7AfEHYF+ywEKs7Q==", "requires": { - "@babel/runtime": "7.15.4", - "@babel/runtime-corejs3": "7.14.7", + "@babel/runtime-corejs3": "7.21.0", "crypto-js": "4.1.1", - "idb-keyval": "5.0.6", + "idb-keyval": "6.2.0", "react-native-crypto-js": "1.0.0", - "uuid": "3.4.0", - "ws": "7.5.1", + "uuid": "9.0.0", + "ws": "8.13.0", "xmlhttprequest": "1.8.0" } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "ws": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", - "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==", - "requires": {} } } }, diff --git a/package.json b/package.json index 26119380ce..2c6fb0a0a3 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@graphql-tools/utils": "8.12.0", "@graphql-yoga/node": "2.6.0", "@parse/fs-files-adapter": "1.2.2", - "@parse/push-adapter": "4.2.0", + "@parse/push-adapter": "5.0.2", "bcryptjs": "2.4.3", "body-parser": "1.20.2", "commander": "10.0.1", From 0762ba6b79d3667b7d1b24818d679c28ce195364 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 18 Nov 2023 13:54:18 +0000 Subject: [PATCH 30/33] chore(release): 6.5.0-alpha.1 [skip ci] # [6.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-alpha.1) (2023-11-18) ### Bug Fixes * Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) * Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) * Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) * Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) ### Features * Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) * Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) * Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) * Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) * Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740)) --- changelogs/CHANGELOG_alpha.md | 18 ++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 5430432163..1054d58dbd 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,21 @@ +# [6.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-alpha.1) (2023-11-18) + + +### Bug Fixes + +* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) +* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) +* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) +* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) + +### Features + +* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) +* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) +* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) +* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) +* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740)) + # [6.4.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.7...6.4.0-alpha.8) (2023-11-13) diff --git a/package-lock.json b/package-lock.json index 41e4ecd8ea..fbc60d0c0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.5.0-beta.1", + "version": "6.5.0-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.5.0-beta.1", + "version": "6.5.0-alpha.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 2c6fb0a0a3..05f60675e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.5.0-beta.1", + "version": "6.5.0-alpha.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 759731926f3017df563eb1cc25196770c14ac3f7 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 18 Nov 2023 15:41:16 +0100 Subject: [PATCH 31/33] docs: Improve docs for Parse Server options `masterKeyIps`, `maintenanceKeyIps` (#8814) --- src/Options/Definitions.js | 4 ++-- src/Options/docs.js | 4 ++-- src/Options/index.js | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index c37e6adfc3..35da35bb5f 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -344,7 +344,7 @@ module.exports.ParseServerOptions = { maintenanceKeyIps: { env: 'PARSE_SERVER_MAINTENANCE_KEY_IPS', help: - "(Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key.", + "(Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key.", action: parsers.arrayParser, default: ['127.0.0.1', '::1'], }, @@ -356,7 +356,7 @@ module.exports.ParseServerOptions = { masterKeyIps: { env: 'PARSE_SERVER_MASTER_KEY_IPS', help: - "(Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key.", + "(Optional) Restricts the use of master key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the master key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the master key.", action: parsers.arrayParser, default: ['127.0.0.1', '::1'], }, diff --git a/src/Options/docs.js b/src/Options/docs.js index cef358ad63..643123c253 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -64,9 +64,9 @@ * @property {LogLevels} logLevels (Optional) Overrides the log levels used internally by Parse Server to log events. * @property {String} logsFolder Folder for the logs (defaults to './logs'); set to null to disable file based logging * @property {String} maintenanceKey (Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. - * @property {String[]} maintenanceKeyIps (Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key. + * @property {String[]} maintenanceKeyIps (Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key. * @property {String} masterKey Your Parse Master Key - * @property {String[]} masterKeyIps (Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key. + * @property {String[]} masterKeyIps (Optional) Restricts the use of master key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the master key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the master key. * @property {Number} maxLimit Max value for limit option on queries, defaults to unlimited * @property {Number|String} maxLogFiles Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null) * @property {String} maxUploadSize Max file size for uploads, defaults to 20mb diff --git a/src/Options/index.js b/src/Options/index.js index 9af83ecd82..cfda946a05 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -52,11 +52,11 @@ export interface ParseServerOptions { /* URL to your parse server with http:// or https://. :ENV: PARSE_SERVER_URL */ serverURL: string; - /* (Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key. + /* (Optional) Restricts the use of master key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the master key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the master key. :DEFAULT: ["127.0.0.1","::1"] */ masterKeyIps: ?(string[]); - /* (Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key. - :DEFAULT: ["127.0.0.1","::1"] */ + /* (Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key. + :DEFAULT: ["127.0.0.1","::1"] */ maintenanceKeyIps: ?(string[]); /* Sets the app name */ appName: ?string; @@ -109,7 +109,7 @@ export interface ParseServerOptions { /* Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`. :DEFAULT: false */ convertEmailToLowercase: ?boolean; - /* Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`. + /* Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`. :DEFAULT: false */ convertUsernameToLowercase: ?boolean; /* Full path to your cloud code main.js */ From b87daba0671a1b0b7b8d63bc671d665c91a04522 Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Sun, 19 Nov 2023 23:13:16 +0100 Subject: [PATCH 32/33] perf: Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` (#8510) --- package-lock.json | 17 ------ package.json | 1 - spec/Middlewares.spec.js | 125 ++++++++++++++++++++++++++++++++------- src/ParseServer.js | 2 + src/middlewares.js | 47 ++++++++++++++- 5 files changed, 151 insertions(+), 41 deletions(-) diff --git a/package-lock.json b/package-lock.json index fbc60d0c0c..eb144c6e58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,6 @@ "graphql-relay": "0.10.0", "graphql-tag": "2.12.6", "intersect": "1.0.1", - "ip-range-check": "0.2.0", "jsonwebtoken": "9.0.0", "jwks-rsa": "2.1.5", "ldapjs": "2.3.3", @@ -9250,14 +9249,6 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, - "node_modules/ip-range-check": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ip-range-check/-/ip-range-check-0.2.0.tgz", - "integrity": "sha512-oaM3l/3gHbLlt/tCWLvt0mj1qUaI+STuRFnUvARGCujK9vvU61+2JsDpmkMzR4VsJhuFXWWgeKKVnwwoFfzCqw==", - "dependencies": { - "ipaddr.js": "^1.0.1" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -27583,14 +27574,6 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, - "ip-range-check": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ip-range-check/-/ip-range-check-0.2.0.tgz", - "integrity": "sha512-oaM3l/3gHbLlt/tCWLvt0mj1qUaI+STuRFnUvARGCujK9vvU61+2JsDpmkMzR4VsJhuFXWWgeKKVnwwoFfzCqw==", - "requires": { - "ipaddr.js": "^1.0.1" - } - }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", diff --git a/package.json b/package.json index 05f60675e5..c1ee3da636 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "graphql-relay": "0.10.0", "graphql-tag": "2.12.6", "intersect": "1.0.1", - "ip-range-check": "0.2.0", "jsonwebtoken": "9.0.0", "jwks-rsa": "2.1.5", "ldapjs": "2.3.3", diff --git a/spec/Middlewares.spec.js b/spec/Middlewares.spec.js index 636e7809f9..7ec50bd434 100644 --- a/spec/Middlewares.spec.js +++ b/spec/Middlewares.spec.js @@ -1,10 +1,19 @@ const middlewares = require('../lib/middlewares'); const AppCache = require('../lib/cache').AppCache; +const { BlockList } = require('net'); + +const AppCachePut = (appId, config) => + AppCache.put(appId, { + ...config, + maintenanceKeyIpsStore: new Map(), + masterKeyIpsStore: new Map(), + }); describe('middlewares', () => { let fakeReq, fakeRes; beforeEach(() => { fakeReq = { + ip: '127.0.0.1', originalUrl: 'http://example.com/parse/', url: 'http://example.com/', body: { @@ -16,7 +25,7 @@ describe('middlewares', () => { }, }; fakeRes = jasmine.createSpyObj('fakeRes', ['end', 'status']); - AppCache.put(fakeReq.body._ApplicationId, {}); + AppCachePut(fakeReq.body._ApplicationId, {}); }); afterEach(() => { @@ -35,7 +44,7 @@ describe('middlewares', () => { }); it('should give invalid response when keys are configured but no key supplied', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', restAPIKey: 'restAPIKey', }); @@ -44,7 +53,7 @@ describe('middlewares', () => { }); it('should give invalid response when keys are configured but supplied key is incorrect', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', restAPIKey: 'restAPIKey', }); @@ -54,7 +63,7 @@ describe('middlewares', () => { }); it('should give invalid response when keys are configured but different key is supplied', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', restAPIKey: 'restAPIKey', }); @@ -64,7 +73,7 @@ describe('middlewares', () => { }); it('should succeed when any one of the configured keys supplied', done => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { clientKey: 'clientKey', masterKey: 'masterKey', restAPIKey: 'restAPIKey', @@ -77,7 +86,7 @@ describe('middlewares', () => { }); it('should succeed when client key supplied but empty', done => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { clientKey: '', masterKey: 'masterKey', restAPIKey: 'restAPIKey', @@ -90,7 +99,7 @@ describe('middlewares', () => { }); it('should succeed when no keys are configured and none supplied', done => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', }); middlewares.handleParseHeaders(fakeReq, fakeRes, () => { @@ -117,7 +126,7 @@ describe('middlewares', () => { otherKey => otherKey !== infoKey && otherKey !== 'javascriptKey' ); it(`it should pull ${bodyKey} into req.info`, done => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKeyIps: ['0.0.0.0/0'], }); fakeReq.ip = '127.0.0.1'; @@ -138,7 +147,7 @@ describe('middlewares', () => { it('should not succeed and log if the ip does not belong to masterKeyIps list', async () => { const logger = require('../lib/logger').logger; spyOn(logger, 'error').and.callFake(() => {}); - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['10.0.0.1'], }); @@ -152,7 +161,7 @@ describe('middlewares', () => { }); it('should not succeed if the ip does not belong to masterKeyIps list', async () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['10.0.0.1'], }); @@ -165,7 +174,7 @@ describe('middlewares', () => { it('should not succeed if the ip does not belong to maintenanceKeyIps list', async () => { const logger = require('../lib/logger').logger; spyOn(logger, 'error').and.callFake(() => {}); - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { maintenanceKey: 'masterKey', maintenanceKeyIps: ['10.0.0.0', '10.0.0.1'], }); @@ -179,7 +188,7 @@ describe('middlewares', () => { }); it('should succeed if the ip does belong to masterKeyIps list', async () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['10.0.0.1'], }); @@ -190,7 +199,7 @@ describe('middlewares', () => { }); it('should allow any ip to use masterKey if masterKeyIps is empty', async () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['0.0.0.0/0'], }); @@ -221,7 +230,7 @@ describe('middlewares', () => { }); it('should set default Access-Control-Allow-Headers if allowHeaders are empty', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { allowHeaders: undefined, }); const headers = {}; @@ -234,7 +243,7 @@ describe('middlewares', () => { allowCrossDomain(fakeReq, res, () => {}); expect(headers['Access-Control-Allow-Headers']).toContain(middlewares.DEFAULT_ALLOWED_HEADERS); - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { allowHeaders: [], }); allowCrossDomain(fakeReq, res, () => {}); @@ -242,7 +251,7 @@ describe('middlewares', () => { }); it('should append custom headers to Access-Control-Allow-Headers if allowHeaders provided', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { allowHeaders: ['Header-1', 'Header-2'], }); const headers = {}; @@ -258,7 +267,7 @@ describe('middlewares', () => { }); it('should set default Access-Control-Allow-Origin if allowOrigin is empty', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { allowOrigin: undefined, }); const headers = {}; @@ -273,7 +282,7 @@ describe('middlewares', () => { }); it('should set custom origin to Access-Control-Allow-Origin if allowOrigin is provided', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { allowOrigin: 'https://parseplatform.org/', }); const headers = {}; @@ -317,7 +326,7 @@ describe('middlewares', () => { }); it('should use user provided on field userFromJWT', done => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', }); fakeReq.userFromJWT = 'fake-user'; @@ -328,11 +337,87 @@ describe('middlewares', () => { }); it('should give invalid response when upload file without x-parse-application-id in header', () => { - AppCache.put(fakeReq.body._ApplicationId, { + AppCachePut(fakeReq.body._ApplicationId, { masterKey: 'masterKey', }); fakeReq.body = Buffer.from('fake-file'); middlewares.handleParseHeaders(fakeReq, fakeRes); expect(fakeRes.status).toHaveBeenCalledWith(403); }); + + it('should match address', () => { + const ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'; + const anotherIpv6 = '::ffff:101.10.0.1'; + const ipv4 = '192.168.0.101'; + const localhostV6 = '::1'; + const localhostV62 = '::ffff:127.0.0.1'; + const localhostV4 = '127.0.0.1'; + + const v6 = [ipv6, anotherIpv6]; + v6.forEach(ip => { + expect(middlewares.checkIp(ip, ['::/0'], new Map())).toBe(true); + expect(middlewares.checkIp(ip, ['::'], new Map())).toBe(true); + expect(middlewares.checkIp(ip, ['0.0.0.0'], new Map())).toBe(false); + expect(middlewares.checkIp(ip, ['0.0.0.0/0'], new Map())).toBe(false); + expect(middlewares.checkIp(ip, ['123.123.123.123'], new Map())).toBe(false); + }); + + expect(middlewares.checkIp(ipv6, [anotherIpv6], new Map())).toBe(false); + expect(middlewares.checkIp(ipv6, [ipv6], new Map())).toBe(true); + expect(middlewares.checkIp(ipv6, ['2001:db8:85a3:0:0:8a2e:0:0/100'], new Map())).toBe(true); + + expect(middlewares.checkIp(ipv4, ['::'], new Map())).toBe(false); + expect(middlewares.checkIp(ipv4, ['::/0'], new Map())).toBe(false); + expect(middlewares.checkIp(ipv4, ['0.0.0.0'], new Map())).toBe(true); + expect(middlewares.checkIp(ipv4, ['0.0.0.0/0'], new Map())).toBe(true); + expect(middlewares.checkIp(ipv4, ['123.123.123.123'], new Map())).toBe(false); + expect(middlewares.checkIp(ipv4, [ipv4], new Map())).toBe(true); + expect(middlewares.checkIp(ipv4, ['192.168.0.0/24'], new Map())).toBe(true); + + expect(middlewares.checkIp(localhostV4, ['::1'], new Map())).toBe(false); + expect(middlewares.checkIp(localhostV6, ['::1'], new Map())).toBe(true); + // ::ffff:127.0.0.1 is a padded ipv4 address but not ::1 + expect(middlewares.checkIp(localhostV62, ['::1'], new Map())).toBe(false); + // ::ffff:127.0.0.1 is a padded ipv4 address and is a match for 127.0.0.1 + expect(middlewares.checkIp(localhostV62, ['127.0.0.1'], new Map())).toBe(true); + }); + + it('should match address with cache', () => { + const ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'; + const cache1 = new Map(); + const spyBlockListCheck = spyOn(BlockList.prototype, 'check').and.callThrough(); + expect(middlewares.checkIp(ipv6, ['::'], cache1)).toBe(true); + expect(cache1.get('2001:0db8:85a3:0000:0000:8a2e:0370:7334')).toBe(undefined); + expect(cache1.get('allowAllIpv6')).toBe(true); + expect(spyBlockListCheck).toHaveBeenCalledTimes(0); + + const cache2 = new Map(); + expect(middlewares.checkIp('::1', ['::1'], cache2)).toBe(true); + expect(cache2.get('::1')).toBe(true); + expect(spyBlockListCheck).toHaveBeenCalledTimes(1); + expect(middlewares.checkIp('::1', ['::1'], cache2)).toBe(true); + expect(spyBlockListCheck).toHaveBeenCalledTimes(1); + spyBlockListCheck.calls.reset(); + + const cache3 = new Map(); + expect(middlewares.checkIp('127.0.0.1', ['127.0.0.1'], cache3)).toBe(true); + expect(cache3.get('127.0.0.1')).toBe(true); + expect(spyBlockListCheck).toHaveBeenCalledTimes(1); + expect(middlewares.checkIp('127.0.0.1', ['127.0.0.1'], cache3)).toBe(true); + expect(spyBlockListCheck).toHaveBeenCalledTimes(1); + spyBlockListCheck.calls.reset(); + + const cache4 = new Map(); + const ranges = ['127.0.0.1', '192.168.0.0/24']; + // should not cache negative match + expect(middlewares.checkIp('123.123.123.123', ranges, cache4)).toBe(false); + expect(cache4.get('123.123.123.123')).toBe(undefined); + expect(spyBlockListCheck).toHaveBeenCalledTimes(1); + spyBlockListCheck.calls.reset(); + + // should not cache cidr + expect(middlewares.checkIp('192.168.0.101', ranges, cache4)).toBe(true); + expect(cache4.get('192.168.0.101')).toBe(undefined); + expect(spyBlockListCheck).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/ParseServer.js b/src/ParseServer.js index 6465e1f3c9..91d151b3f9 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -75,6 +75,8 @@ class ParseServer { const allControllers = controllers.getControllers(options); options.state = 'initialized'; this.config = Config.put(Object.assign({}, options, allControllers)); + this.config.masterKeyIpsStore = new Map(); + this.config.maintenanceKeyIpsStore = new Map(); logging.setLogger(allControllers.loggerController); } diff --git a/src/middlewares.js b/src/middlewares.js index a7e309b0cc..9319130188 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -10,9 +10,9 @@ import PostgresStorageAdapter from './Adapters/Storage/Postgres/PostgresStorageA import rateLimit from 'express-rate-limit'; import { RateLimitOptions } from './Options/Definitions'; import { pathToRegexp } from 'path-to-regexp'; -import ipRangeCheck from 'ip-range-check'; import RedisStore from 'rate-limit-redis'; import { createClient } from 'redis'; +import { BlockList, isIPv4 } from 'net'; export const DEFAULT_ALLOWED_HEADERS = 'X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, X-Parse-Request-Id, Content-Type, Pragma, Cache-Control'; @@ -23,6 +23,46 @@ const getMountForRequest = function (req) { return req.protocol + '://' + req.get('host') + mountPath; }; +const getBlockList = (ipRangeList, store) => { + if (store.get('blockList')) return store.get('blockList'); + const blockList = new BlockList(); + ipRangeList.forEach(fullIp => { + if (fullIp === '::/0' || fullIp === '::') { + store.set('allowAllIpv6', true); + return; + } + if (fullIp === '0.0.0.0/0' || fullIp === '0.0.0.0') { + store.set('allowAllIpv4', true); + return; + } + const [ip, mask] = fullIp.split('/'); + if (!mask) { + blockList.addAddress(ip, isIPv4(ip) ? 'ipv4' : 'ipv6'); + } else { + blockList.addSubnet(ip, Number(mask), isIPv4(ip) ? 'ipv4' : 'ipv6'); + } + }); + store.set('blockList', blockList); + return blockList; +}; + +export const checkIp = (ip, ipRangeList, store) => { + const incomingIpIsV4 = isIPv4(ip); + const blockList = getBlockList(ipRangeList, store); + + if (store.get(ip)) return true; + if (store.get('allowAllIpv4') && incomingIpIsV4) return true; + if (store.get('allowAllIpv6') && !incomingIpIsV4) return true; + const result = blockList.check(ip, incomingIpIsV4 ? 'ipv4' : 'ipv6'); + + // If the ip is in the list, we store the result in the store + // so we have a optimized path for the next request + if (ipRangeList.includes(ip) && result) { + store.set(ip, result); + } + return result; +}; + // Checks that the request is authorized for this app and checks user // auth too. // The bodyparser should run before this middleware. @@ -183,7 +223,7 @@ export function handleParseHeaders(req, res, next) { const isMaintenance = req.config.maintenanceKey && info.maintenanceKey === req.config.maintenanceKey; if (isMaintenance) { - if (ipRangeCheck(clientIp, req.config.maintenanceKeyIps || [])) { + if (checkIp(clientIp, req.config.maintenanceKeyIps || [], req.config.maintenanceKeyIpsStore)) { req.auth = new auth.Auth({ config: req.config, installationId: info.installationId, @@ -199,7 +239,8 @@ export function handleParseHeaders(req, res, next) { } let isMaster = info.masterKey === req.config.masterKey; - if (isMaster && !ipRangeCheck(clientIp, req.config.masterKeyIps || [])) { + + if (isMaster && !checkIp(clientIp, req.config.masterKeyIps || [], req.config.masterKeyIpsStore)) { const log = req.config?.loggerController || defaultLogger; log.error( `Request using master key rejected as the request IP address '${clientIp}' is not set in Parse Server option 'masterKeyIps'.` From d3087ed69f9745848729951171657b79d3192469 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 19 Nov 2023 22:14:13 +0000 Subject: [PATCH 33/33] chore(release): 6.5.0-alpha.2 [skip ci] # [6.5.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.5.0-alpha.1...6.5.0-alpha.2) (2023-11-19) ### Performance Improvements * Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 1054d58dbd..04560985ab 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.5.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.5.0-alpha.1...6.5.0-alpha.2) (2023-11-19) + + +### Performance Improvements + +* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522)) + # [6.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-alpha.1) (2023-11-18) diff --git a/package-lock.json b/package-lock.json index eb144c6e58..3f1eec3e28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.5.0-alpha.1", + "version": "6.5.0-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.5.0-alpha.1", + "version": "6.5.0-alpha.2", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index c1ee3da636..3c0c9e5eb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.5.0-alpha.1", + "version": "6.5.0-alpha.2", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": {