From 40c196153b8efa12ae384c1c0092b2ed60a260d6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 4 Mar 2023 03:51:45 +1100 Subject: [PATCH 01/21] feat: Export `AuthAdapter` to make it available for extension with custom authentication adapters (#8443) --- src/Adapters/Auth/index.js | 29 +++++++++++++++++++---------- src/index.js | 2 ++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 0338bfdcea..79a9e9e0bf 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -1,5 +1,6 @@ import loadAdapter from '../AdapterLoader'; import Parse from 'parse/node'; +import AuthAdapter from './AuthAdapter'; const apple = require('./apple'); const gcenter = require('./gcenter'); @@ -153,22 +154,30 @@ function loadAuthAdapter(provider, authOptions) { return; } - const adapter = Object.assign({}, defaultAdapter); + const adapter = defaultAdapter instanceof AuthAdapter ? defaultAdapter : Object.assign({}, defaultAdapter); + const keys = [ + 'validateAuthData', + 'validateAppId', + 'validateSetUp', + 'validateLogin', + 'validateUpdate', + 'challenge', + 'policy' + ]; + const defaultAuthAdapter = new AuthAdapter(); + keys.forEach(key => { + const existing = adapter?.[key]; + if (existing && typeof existing === 'function' && existing.toString() === defaultAuthAdapter[key].toString()) { + adapter[key] = null; + } + }); const appIds = providerOptions ? providerOptions.appIds : undefined; // Try the configuration methods if (providerOptions) { const optionalAdapter = loadAdapter(providerOptions, undefined, providerOptions); if (optionalAdapter) { - [ - 'validateAuthData', - 'validateAppId', - 'validateSetUp', - 'validateLogin', - 'validateUpdate', - 'challenge', - 'policy', - ].forEach(key => { + keys.forEach(key => { if (optionalAdapter[key]) { adapter[key] = optionalAdapter[key]; } diff --git a/src/index.js b/src/index.js index 684443ce5b..dcfe9b4c7e 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import RedisCacheAdapter from './Adapters/Cache/RedisCacheAdapter'; import LRUCacheAdapter from './Adapters/Cache/LRUCache.js'; import * as TestUtils from './TestUtils'; import * as SchemaMigrations from './SchemaMigrations/Migrations'; +import AuthAdapter from './Adapters/Auth/AuthAdapter'; import { useExternal } from './deprecated'; import { getLogger } from './logger'; @@ -43,4 +44,5 @@ export { ParseGraphQLServer, _ParseServer as ParseServer, SchemaMigrations, + AuthAdapter, }; From 3f5b2900a6870e2d25605b08fdb9a32e575dc69d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 3 Mar 2023 16:52:51 +0000 Subject: [PATCH 02/21] chore(release): 6.1.0-alpha.1 [skip ci] # [6.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-alpha.1) (2023-03-03) ### Bug Fixes * Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164)) ### Features * Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323)) * Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b)) * Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1)) * Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6)) --- changelogs/CHANGELOG_alpha.md | 14 ++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 18eb32b574..a0f9906b42 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,17 @@ +# [6.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-alpha.1) (2023-03-03) + + +### Bug Fixes + +* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164)) + +### Features + +* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323)) +* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b)) +* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1)) +* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6)) + # [6.0.0-alpha.35](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.34...6.0.0-alpha.35) (2023-02-27) diff --git a/package-lock.json b/package-lock.json index fe5a6edfc0..d20dc8fc8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-beta.1", + "version": "6.1.0-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-beta.1", + "version": "6.1.0-alpha.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 5cf9788023..15b11f4097 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-beta.1", + "version": "6.1.0-alpha.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 22d2446dfea2bc339affc20535d181097e152acf Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 5 Mar 2023 11:22:19 +1100 Subject: [PATCH 03/21] fix: Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object (#8446) --- spec/MongoStorageAdapter.spec.js | 4 ++++ src/Adapters/Storage/Mongo/MongoTransform.js | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index 58731d2432..06fdab4fca 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -248,6 +248,10 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { expect(object.date[0] instanceof Date).toBeTrue(); expect(object.bar.date[0] instanceof Date).toBeTrue(); expect(object.foo.test.date[0] instanceof Date).toBeTrue(); + const obj = await new Parse.Query('MyClass').first({useMasterKey: true}); + expect(obj.get('date')[0] instanceof Date).toBeTrue(); + expect(obj.get('bar').date[0] instanceof Date).toBeTrue(); + expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue(); }); it('handles updating a single object with array, object date', done => { diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index aabf744978..6f6811cec3 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -188,6 +188,16 @@ const transformInteriorValue = restValue => { // Handle atomic values var value = transformInteriorAtom(restValue); if (value !== CannotTransform) { + if (value && typeof value === 'object') { + if (value instanceof Date) { + return value; + } + if (value instanceof Array) { + value = value.map(transformInteriorValue); + } else { + value = mapValues(value, transformInteriorValue); + } + } return value; } @@ -1014,9 +1024,6 @@ function mapValues(object, iterator) { const result = {}; Object.keys(object).forEach(key => { result[key] = iterator(object[key]); - if (result[key] && JSON.stringify(result[key]).includes(`"__type"`)) { - result[key] = mapValues(object[key], iterator); - } }); return result; } From 94d558edbb72862aa92fcb211c3c657617d0a5f9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 5 Mar 2023 00:23:27 +0000 Subject: [PATCH 04/21] chore(release): 6.1.0-alpha.2 [skip ci] # [6.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.1...6.1.0-alpha.2) (2023-03-05) ### Bug Fixes * Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf)) --- 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 a0f9906b42..b59f3107d4 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.1...6.1.0-alpha.2) (2023-03-05) + + +### Bug Fixes + +* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf)) + # [6.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-alpha.1) (2023-03-03) diff --git a/package-lock.json b/package-lock.json index d20dc8fc8d..2abb66b241 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.1", + "version": "6.1.0-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.1", + "version": "6.1.0-alpha.2", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 15b11f4097..392237290b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.1", + "version": "6.1.0-alpha.2", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 87cab09b6ad555409241b76c10c61ce1320046bd Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 5 Mar 2023 18:16:04 -0500 Subject: [PATCH 05/21] refactor: Upgrade pg-promise to 11.3.0 and pg-monitor to 2.0.0 (#8453) --- package-lock.json | 82 +++++++++---------- package.json | 4 +- spec/PostgresConfigParser.spec.js | 20 ++++- .../Storage/Postgres/PostgresConfigParser.js | 2 +- 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2abb66b241..a6aa102a23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,8 +41,8 @@ "mustache": "4.2.0", "parse": "4.0.1", "path-to-regexp": "0.1.7", - "pg-monitor": "1.5.0", - "pg-promise": "10.12.1", + "pg-monitor": "2.0.0", + "pg-promise": "11.3.0", "pluralize": "8.0.0", "redis": "4.0.6", "semver": "7.3.8", @@ -4060,11 +4060,11 @@ } }, "node_modules/assert-options": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.7.0.tgz", - "integrity": "sha512-7q9uNH/Dh8gFgpIIb9ja8PJEWA5AQy3xnBC8jtKs8K/gNVCr1K6kIvlm59HUyYgvM7oEDoLzGgPcGd9FqhtXEQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.0.tgz", + "integrity": "sha512-qSELrEaEz4sGwTs4Qh+swQkjiHAysC4rot21+jzXU86dJzNG+FDqBzyS3ohSoTRf4ZLA3FSwxQdiuNl5NXUtvA==", "engines": { - "node": ">=8.0.0" + "node": ">=10.0.0" } }, "node_modules/assert-plus": { @@ -16069,15 +16069,15 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/pg": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", - "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.9.0.tgz", + "integrity": "sha512-ZJM+qkEbtOHRuXjmvBtOgNOXOtLSbxiMiUVMgE4rV6Zwocy03RicCVvDXgx8l4Biwo8/qORUnEqn2fdQzV7KCg==", "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "^2.5.0", "pg-pool": "^3.5.2", - "pg-protocol": "^1.5.0", + "pg-protocol": "^1.6.0", "pg-types": "^2.1.0", "pgpass": "1.x" }, @@ -16115,14 +16115,14 @@ } }, "node_modules/pg-monitor": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-1.5.0.tgz", - "integrity": "sha512-Zg5RpoYaz0zyRwAQWKrRxUZgzZ+/r4McMP4vEvg+qE8765SHAB1wHZL58uAjocG4WSK/NLP/zZhUuoyurw4l6Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-2.0.0.tgz", + "integrity": "sha512-UqjhroM701sRrJHhXeF1OwNBGxkN9R0YgkVU8A46wWn3RwK/K7QDylChMoDxo8TmGp86CBP4ZSf+RK9vD8XyVA==", "dependencies": { "cli-color": "2.0.3" }, "engines": { - "node": ">=7.6" + "node": ">=14" } }, "node_modules/pg-monitor/node_modules/cli-color": { @@ -16189,23 +16189,23 @@ } }, "node_modules/pg-promise": { - "version": "10.12.1", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.12.1.tgz", - "integrity": "sha512-SiJkBUDGq7PNfJFJbWferodsSH+vLrhte0Q0kVgQbwlNYeKmp9Hhkr+357+5DWEuBGOHhSu1UQffSSf5HVqRtA==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.3.0.tgz", + "integrity": "sha512-A2CYmax5gsqVAO2N0ET9oPRCPX3kpKymj9qLVK7+jszlJL6l8uJDq/DGqLpxNi5VHwK7Dmm2WNRdrwkh1xuaxQ==", "dependencies": { - "assert-options": "0.7.0", - "pg": "8.8.0", + "assert-options": "0.8.0", + "pg": "8.9.0", "pg-minify": "1.6.2", "spex": "3.2.0" }, "engines": { - "node": ">=12.0" + "node": ">=14.0" } }, "node_modules/pg-protocol": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", - "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" }, "node_modules/pg-types": { "version": "2.2.0", @@ -23386,9 +23386,9 @@ } }, "assert-options": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.7.0.tgz", - "integrity": "sha512-7q9uNH/Dh8gFgpIIb9ja8PJEWA5AQy3xnBC8jtKs8K/gNVCr1K6kIvlm59HUyYgvM7oEDoLzGgPcGd9FqhtXEQ==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.0.tgz", + "integrity": "sha512-qSELrEaEz4sGwTs4Qh+swQkjiHAysC4rot21+jzXU86dJzNG+FDqBzyS3ohSoTRf4ZLA3FSwxQdiuNl5NXUtvA==" }, "assert-plus": { "version": "1.0.0", @@ -32524,15 +32524,15 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "pg": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", - "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.9.0.tgz", + "integrity": "sha512-ZJM+qkEbtOHRuXjmvBtOgNOXOtLSbxiMiUVMgE4rV6Zwocy03RicCVvDXgx8l4Biwo8/qORUnEqn2fdQzV7KCg==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "^2.5.0", "pg-pool": "^3.5.2", - "pg-protocol": "^1.5.0", + "pg-protocol": "^1.6.0", "pg-types": "^2.1.0", "pgpass": "1.x" } @@ -32553,9 +32553,9 @@ "integrity": "sha512-1KdmFGGTP6jplJoI8MfvRlfvMiyBivMRP7/ffh4a11RUFJ7kC2J0ZHlipoKiH/1hz+DVgceon9U2qbaHpPeyPg==" }, "pg-monitor": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-1.5.0.tgz", - "integrity": "sha512-Zg5RpoYaz0zyRwAQWKrRxUZgzZ+/r4McMP4vEvg+qE8765SHAB1wHZL58uAjocG4WSK/NLP/zZhUuoyurw4l6Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-2.0.0.tgz", + "integrity": "sha512-UqjhroM701sRrJHhXeF1OwNBGxkN9R0YgkVU8A46wWn3RwK/K7QDylChMoDxo8TmGp86CBP4ZSf+RK9vD8XyVA==", "requires": { "cli-color": "2.0.3" }, @@ -32621,20 +32621,20 @@ "requires": {} }, "pg-promise": { - "version": "10.12.1", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.12.1.tgz", - "integrity": "sha512-SiJkBUDGq7PNfJFJbWferodsSH+vLrhte0Q0kVgQbwlNYeKmp9Hhkr+357+5DWEuBGOHhSu1UQffSSf5HVqRtA==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.3.0.tgz", + "integrity": "sha512-A2CYmax5gsqVAO2N0ET9oPRCPX3kpKymj9qLVK7+jszlJL6l8uJDq/DGqLpxNi5VHwK7Dmm2WNRdrwkh1xuaxQ==", "requires": { - "assert-options": "0.7.0", - "pg": "8.8.0", + "assert-options": "0.8.0", + "pg": "8.9.0", "pg-minify": "1.6.2", "spex": "3.2.0" } }, "pg-protocol": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", - "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" }, "pg-types": { "version": "2.2.0", diff --git a/package.json b/package.json index 392237290b..89964cfb76 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,8 @@ "mustache": "4.2.0", "parse": "4.0.1", "path-to-regexp": "0.1.7", - "pg-monitor": "1.5.0", - "pg-promise": "10.12.1", + "pg-monitor": "2.0.0", + "pg-promise": "11.3.0", "pluralize": "8.0.0", "redis": "4.0.6", "semver": "7.3.8", diff --git a/spec/PostgresConfigParser.spec.js b/spec/PostgresConfigParser.spec.js index 412e7b20b9..f4efc42114 100644 --- a/spec/PostgresConfigParser.spec.js +++ b/spec/PostgresConfigParser.spec.js @@ -27,13 +27,13 @@ const baseURI = 'postgres://username:password@localhost:5432/db-name'; const testfile = fs.readFileSync('./Dockerfile').toString(); const dbOptionsTest = {}; dbOptionsTest[ - `${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=10` + `${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=12` ] = { ssl: true, binary: true, application_name: 'app_name', fallback_application_name: 'f_app_name', - poolSize: 10, + max: 12, }; dbOptionsTest[`${baseURI}?ssl=&binary=aa`] = { binary: false, @@ -83,6 +83,20 @@ describe('PostgresConfigParser.getDatabaseOptionsFromURI', () => { it('sets the poolSize to 10 if the it is not a number', () => { const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=sdf`); - expect(result.poolSize).toEqual(10); + expect(result.max).toEqual(10); + }); + + it('sets the max to 10 if the it is not a number', () => { + const result = parser.getDatabaseOptionsFromURI(`${baseURI}?&max=sdf`); + + expect(result.poolSize).toBeUndefined(); + expect(result.max).toEqual(10); + }); + + it('max should take precedence over poolSize', () => { + const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=20&max=12`); + + expect(result.poolSize).toBeUndefined(); + expect(result.max).toEqual(12); }); }); diff --git a/src/Adapters/Storage/Postgres/PostgresConfigParser.js b/src/Adapters/Storage/Postgres/PostgresConfigParser.js index d86778cf20..64e4752913 100644 --- a/src/Adapters/Storage/Postgres/PostgresConfigParser.js +++ b/src/Adapters/Storage/Postgres/PostgresConfigParser.js @@ -58,7 +58,7 @@ function getDatabaseOptionsFromURI(uri) { databaseOptions.fallback_application_name = queryParams.fallback_application_name; if (queryParams.poolSize) { - databaseOptions.poolSize = parseInt(queryParams.poolSize) || 10; + databaseOptions.max = parseInt(queryParams.poolSize) || 10; } if (queryParams.max) { databaseOptions.max = parseInt(queryParams.max) || 10; From c793bb88e7485743c7ceb65fe419cde75833ff33 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 6 Mar 2023 11:35:15 +1100 Subject: [PATCH 06/21] feat: Add `afterFind` trigger to authentication adapters (#8444) --- spec/AuthenticationAdaptersV2.spec.js | 24 +++++++++++++++ spec/MongoStorageAdapter.spec.js | 2 +- src/Adapters/Auth/AuthAdapter.js | 18 ++++++++++++ src/Adapters/Auth/index.js | 42 +++++++++++++++++++++++++-- src/RestQuery.js | 12 ++++++++ src/Routers/UsersRouter.js | 1 + 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/spec/AuthenticationAdaptersV2.spec.js b/spec/AuthenticationAdaptersV2.spec.js index 244349a89f..4c63b9a1ef 100644 --- a/spec/AuthenticationAdaptersV2.spec.js +++ b/spec/AuthenticationAdaptersV2.spec.js @@ -59,6 +59,19 @@ describe('Auth Adapter features', () => { validateLogin: () => Promise.resolve(), }; + const modernAdapter3 = { + validateAppId: () => Promise.resolve(), + validateSetUp: () => Promise.resolve(), + validateUpdate: () => Promise.resolve(), + validateLogin: () => Promise.resolve(), + validateOptions: () => Promise.resolve(), + afterFind() { + return { + foo: 'bar', + }; + }, + }; + const wrongAdapter = { validateAppId: () => Promise.resolve(), }; @@ -332,6 +345,17 @@ describe('Auth Adapter features', () => { expect(user.getSessionToken()).toBeDefined(); }); + it('should strip out authData if required', async () => { + const spy = spyOn(modernAdapter3, 'validateOptions').and.callThrough(); + await reconfigureServer({ auth: { modernAdapter3 }, silent: false }); + const user = new Parse.User(); + await user.save({ authData: { modernAdapter3: { id: 'modernAdapter3Data' } } }); + await user.fetch({ sessionToken: user.getSessionToken() }); + const authData = user.get('authData').modernAdapter3; + expect(authData).toEqual({ foo: 'bar' }); + expect(spy).toHaveBeenCalled(); + }); + it('should throw if no triggers found', async () => { await reconfigureServer({ auth: { wrongAdapter } }); const user = new Parse.User(); diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index 06fdab4fca..1b5cc0c5e9 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -248,7 +248,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { expect(object.date[0] instanceof Date).toBeTrue(); expect(object.bar.date[0] instanceof Date).toBeTrue(); expect(object.foo.test.date[0] instanceof Date).toBeTrue(); - const obj = await new Parse.Query('MyClass').first({useMasterKey: true}); + const obj = await new Parse.Query('MyClass').first({ useMasterKey: true }); expect(obj.get('date')[0] instanceof Date).toBeTrue(); expect(obj.get('bar').date[0] instanceof Date).toBeTrue(); expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue(); diff --git a/src/Adapters/Auth/AuthAdapter.js b/src/Adapters/Auth/AuthAdapter.js index 0e106014d5..5b18c75170 100644 --- a/src/Adapters/Auth/AuthAdapter.js +++ b/src/Adapters/Auth/AuthAdapter.js @@ -93,6 +93,24 @@ export class AuthAdapter { challenge(challengeData, authData, options, request) { return Promise.resolve({}); } + + /** + * Triggered when auth data is fetched + * @param {Object} authData authData + * @param {Object} options additional adapter options + * @returns {Promise} Any overrides required to authData + */ + afterFind(authData, options) { + return Promise.resolve({}); + } + + /** + * Triggered when the adapter is first attached to Parse Server + * @param {Object} options Adapter Options + */ + validateOptions(options) { + /* */ + } } export default AuthAdapter; diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 79a9e9e0bf..3440208ebd 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -154,7 +154,8 @@ function loadAuthAdapter(provider, authOptions) { return; } - const adapter = defaultAdapter instanceof AuthAdapter ? defaultAdapter : Object.assign({}, defaultAdapter); + const adapter = + defaultAdapter instanceof AuthAdapter ? defaultAdapter : Object.assign({}, defaultAdapter); const keys = [ 'validateAuthData', 'validateAppId', @@ -162,12 +163,18 @@ function loadAuthAdapter(provider, authOptions) { 'validateLogin', 'validateUpdate', 'challenge', - 'policy' + 'validateOptions', + 'policy', + 'afterFind', ]; const defaultAuthAdapter = new AuthAdapter(); keys.forEach(key => { const existing = adapter?.[key]; - if (existing && typeof existing === 'function' && existing.toString() === defaultAuthAdapter[key].toString()) { + if ( + existing && + typeof existing === 'function' && + existing.toString() === defaultAuthAdapter[key].toString() + ) { adapter[key] = null; } }); @@ -184,6 +191,9 @@ function loadAuthAdapter(provider, authOptions) { }); } } + if (adapter.validateOptions) { + adapter.validateOptions(providerOptions); + } return { adapter, appIds, providerOptions }; } @@ -204,9 +214,35 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) { return { validator: authDataValidator(provider, adapter, appIds, providerOptions), adapter }; }; + const runAfterFind = async authData => { + if (!authData) { + return; + } + const adapters = Object.keys(authData); + await Promise.all( + adapters.map(async provider => { + const authAdapter = getValidatorForProvider(provider); + if (!authAdapter) { + return; + } + const { + adapter: { afterFind }, + providerOptions, + } = authAdapter; + if (afterFind && typeof afterFind === 'function') { + const result = afterFind(authData[provider], providerOptions); + if (result) { + authData[provider] = result; + } + } + }) + ); + }; + return Object.freeze({ getValidatorForProvider, setEnableAnonymousUsers, + runAfterFind, }); }; diff --git a/src/RestQuery.js b/src/RestQuery.js index f936a5a7a8..1f4304e78a 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -223,6 +223,9 @@ RestQuery.prototype.execute = function (executeOptions) { .then(() => { return this.runAfterFindTrigger(); }) + .then(() => { + return this.handleAuthAdapters(); + }) .then(() => { return this.response; }); @@ -842,6 +845,15 @@ RestQuery.prototype.runAfterFindTrigger = function () { }); }; +RestQuery.prototype.handleAuthAdapters = async function () { + if (this.className !== '_User' || this.findOptions.explain) { + return; + } + await Promise.all( + this.response.results.map(result => this.config.authDataManager.runAfterFind(result.authData)) + ); +}; + // Adds included values to the response. // Path is a list of field names. // Returns a promise for an augmented response. diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index 4a72fdd73b..e26d2ef141 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -292,6 +292,7 @@ export class UsersRouter extends ClassesRouter { if (authDataResponse) { user.authDataResponse = authDataResponse; } + await req.config.authDataManager.runAfterFind(user.authData); return { response: user }; } From d05cfcdb950bc87ecbc652e493d47733cf7297b1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Mar 2023 00:36:40 +0000 Subject: [PATCH 07/21] chore(release): 6.1.0-alpha.3 [skip ci] # [6.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.2...6.1.0-alpha.3) (2023-03-06) ### Features * Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33)) --- 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 b59f3107d4..a80d68ba4f 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.2...6.1.0-alpha.3) (2023-03-06) + + +### Features + +* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33)) + # [6.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.1...6.1.0-alpha.2) (2023-03-05) diff --git a/package-lock.json b/package-lock.json index a6aa102a23..7207bf941d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.2", + "version": "6.1.0-alpha.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.2", + "version": "6.1.0-alpha.3", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 89964cfb76..3495ae0e0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.2", + "version": "6.1.0-alpha.3", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From ce34747e8af54cb0b6b975da38f779a5955d2d59 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 6 Mar 2023 13:18:00 +1100 Subject: [PATCH 08/21] fix: Parameters missing in `afterFind` trigger of authentication adapters (#8458) --- spec/AuthenticationAdaptersV2.spec.js | 13 +++++++++++++ src/Adapters/Auth/index.js | 9 +++++++-- src/RestQuery.js | 7 ++++++- src/Routers/UsersRouter.js | 2 +- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/spec/AuthenticationAdaptersV2.spec.js b/spec/AuthenticationAdaptersV2.spec.js index 4c63b9a1ef..9507691114 100644 --- a/spec/AuthenticationAdaptersV2.spec.js +++ b/spec/AuthenticationAdaptersV2.spec.js @@ -347,12 +347,25 @@ describe('Auth Adapter features', () => { it('should strip out authData if required', async () => { const spy = spyOn(modernAdapter3, 'validateOptions').and.callThrough(); + const afterSpy = spyOn(modernAdapter3, 'afterFind').and.callThrough(); await reconfigureServer({ auth: { modernAdapter3 }, silent: false }); const user = new Parse.User(); await user.save({ authData: { modernAdapter3: { id: 'modernAdapter3Data' } } }); await user.fetch({ sessionToken: user.getSessionToken() }); const authData = user.get('authData').modernAdapter3; expect(authData).toEqual({ foo: 'bar' }); + for (const call of afterSpy.calls.all()) { + const args = call.args[0]; + if (args.user) { + user._objCount = args.user._objCount; + break; + } + } + expect(afterSpy).toHaveBeenCalledWith( + { ip: '127.0.0.1', user, master: false }, + { id: 'modernAdapter3Data' }, + undefined + ); expect(spy).toHaveBeenCalled(); }); diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 3440208ebd..2defcb0dc0 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -214,7 +214,7 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) { return { validator: authDataValidator(provider, adapter, appIds, providerOptions), adapter }; }; - const runAfterFind = async authData => { + const runAfterFind = async (req, authData) => { if (!authData) { return; } @@ -230,7 +230,12 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) { providerOptions, } = authAdapter; if (afterFind && typeof afterFind === 'function') { - const result = afterFind(authData[provider], providerOptions); + const requestObject = { + ip: req.config.ip, + user: req.auth.user, + master: req.auth.isMaster, + }; + const result = afterFind(requestObject, authData[provider], providerOptions); if (result) { authData[provider] = result; } diff --git a/src/RestQuery.js b/src/RestQuery.js index 1f4304e78a..fe3617eb1b 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -850,7 +850,12 @@ RestQuery.prototype.handleAuthAdapters = async function () { return; } await Promise.all( - this.response.results.map(result => this.config.authDataManager.runAfterFind(result.authData)) + this.response.results.map(result => + this.config.authDataManager.runAfterFind( + { config: this.config, auth: this.auth }, + result.authData + ) + ) ); }; diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index e26d2ef141..feca46e802 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -292,7 +292,7 @@ export class UsersRouter extends ClassesRouter { if (authDataResponse) { user.authDataResponse = authDataResponse; } - await req.config.authDataManager.runAfterFind(user.authData); + await req.config.authDataManager.runAfterFind(req, user.authData); return { response: user }; } From 6613872ce2da5caebce21f92a315347daf373743 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Mar 2023 02:19:01 +0000 Subject: [PATCH 09/21] chore(release): 6.1.0-alpha.4 [skip ci] # [6.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.3...6.1.0-alpha.4) (2023-03-06) ### Bug Fixes * Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59)) --- 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 a80d68ba4f..d2e76e7629 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.3...6.1.0-alpha.4) (2023-03-06) + + +### Bug Fixes + +* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59)) + # [6.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.2...6.1.0-alpha.3) (2023-03-06) diff --git a/package-lock.json b/package-lock.json index 7207bf941d..83a7606c7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.3", + "version": "6.1.0-alpha.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.3", + "version": "6.1.0-alpha.4", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 3495ae0e0d..32ef8afa37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.3", + "version": "6.1.0-alpha.4", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 4ce135a4fe930776044bc8fd786a4e17a0144e03 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 6 Mar 2023 21:26:06 +1100 Subject: [PATCH 10/21] fix: LiveQuery can return incorrectly formatted date (#8456) --- spec/ParseLiveQueryServer.spec.js | 47 +++++++++++++++++++++++++-- src/LiveQuery/ParseLiveQueryServer.js | 3 +- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/spec/ParseLiveQueryServer.spec.js b/spec/ParseLiveQueryServer.spec.js index 5b4690ae85..16654cdd64 100644 --- a/spec/ParseLiveQueryServer.spec.js +++ b/spec/ParseLiveQueryServer.spec.js @@ -754,6 +754,49 @@ describe('ParseLiveQueryServer', function () { parseLiveQueryServer._onAfterSave(message); }); + it('sends correct object for dates', async () => { + jasmine.restoreLibrary('../lib/LiveQuery/QueryTools', 'matchesQuery'); + + const parseLiveQueryServer = new ParseLiveQueryServer({}); + + const date = new Date(); + const message = { + currentParseObject: { + date: { __type: 'Date', iso: date.toISOString() }, + __type: 'Object', + key: 'value', + className: testClassName, + }, + }; + // Add mock client + const clientId = 1; + const client = addMockClient(parseLiveQueryServer, clientId); + + const requestId2 = 2; + + await addMockSubscription(parseLiveQueryServer, clientId, requestId2); + + parseLiveQueryServer._matchesACL = function () { + return Promise.resolve(true); + }; + + parseLiveQueryServer._inflateParseObject(message); + parseLiveQueryServer._onAfterSave(message); + + // Make sure we send leave and enter command to client + await timeout(); + + expect(client.pushCreate).toHaveBeenCalledWith( + requestId2, + { + className: 'TestObject', + key: 'value', + date: { __type: 'Date', iso: date.toISOString() }, + }, + null + ); + }); + it('can handle object save command which does not match any subscription', async done => { const parseLiveQueryServer = new ParseLiveQueryServer({}); // Make mock request message @@ -1138,8 +1181,7 @@ describe('ParseLiveQueryServer', function () { expect(toSend.original).toBeUndefined(); expect(spy).toHaveBeenCalledWith({ usage: 'Subscribing using fields parameter', - solution: - `Subscribe using "keys" instead.`, + solution: `Subscribe using "keys" instead.`, }); }); @@ -1945,6 +1987,7 @@ describe('ParseLiveQueryServer', function () { } else { subscription.clientRequestIds = new Map([[clientId, [requestId]]]); } + subscription.query = query.where; return subscription; } diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 934a556966..0b71265f33 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -24,6 +24,7 @@ import UserRouter from '../Routers/UsersRouter'; import DatabaseController from '../Controllers/DatabaseController'; import { isDeepStrictEqual } from 'util'; import Deprecator from '../Deprecator/Deprecator'; +import deepcopy from 'deepcopy'; class ParseLiveQueryServer { clients: Map; @@ -496,7 +497,7 @@ class ParseLiveQueryServer { if (!parseObject) { return false; } - return matchesQuery(parseObject, subscription.query); + return matchesQuery(deepcopy(parseObject), subscription.query); } async _clearCachedRoles(userId: string) { From 0f1979f814f69b8994cbf84949f6dcf659053d26 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Mar 2023 10:27:30 +0000 Subject: [PATCH 11/21] chore(release): 6.1.0-alpha.5 [skip ci] # [6.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.4...6.1.0-alpha.5) (2023-03-06) ### Bug Fixes * LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03)) --- 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 d2e76e7629..c1062d350b 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.4...6.1.0-alpha.5) (2023-03-06) + + +### Bug Fixes + +* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03)) + # [6.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.3...6.1.0-alpha.4) (2023-03-06) diff --git a/package-lock.json b/package-lock.json index 83a7606c7f..4199bbc70a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.4", + "version": "6.1.0-alpha.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.4", + "version": "6.1.0-alpha.5", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 32ef8afa37..2d4e0e071a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.4", + "version": "6.1.0-alpha.5", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 34833e42eec08b812b733be78df0535ab0e096b6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Mar 2023 03:43:15 +1100 Subject: [PATCH 12/21] feat: Add rate limiting across multiple servers via Redis (#8394) --- package-lock.json | 18 ++++++++++++++++++ package.json | 1 + spec/RateLimit.spec.js | 30 ++++++++++++++++++++++++++++++ src/Options/Definitions.js | 5 +++++ src/Options/docs.js | 1 + src/Options/index.js | 3 +++ src/middlewares.js | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 90 insertions(+) diff --git a/package-lock.json b/package-lock.json index 4199bbc70a..e97746c926 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "pg-monitor": "2.0.0", "pg-promise": "11.3.0", "pluralize": "8.0.0", + "rate-limit-redis": "3.0.1", "redis": "4.0.6", "semver": "7.3.8", "subscriptions-transport-ws": "0.11.0", @@ -16746,6 +16747,17 @@ "node": ">= 0.6" } }, + "node_modules/rate-limit-redis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-3.0.1.tgz", + "integrity": "sha512-L6yhOUBrAZ8VEMX9DwlM3X6hfm8yq+gBO4LoOW7+JgmNq59zE7QmLz4v5VnwYPvLeSh/e7PDcrzUI3UumJw1iw==", + "engines": { + "node": ">= 14.5.0" + }, + "peerDependencies": { + "express-rate-limit": "^6" + } + }, "node_modules/raw-body": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", @@ -33032,6 +33044,12 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "rate-limit-redis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-3.0.1.tgz", + "integrity": "sha512-L6yhOUBrAZ8VEMX9DwlM3X6hfm8yq+gBO4LoOW7+JgmNq59zE7QmLz4v5VnwYPvLeSh/e7PDcrzUI3UumJw1iw==", + "requires": {} + }, "raw-body": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", diff --git a/package.json b/package.json index 2d4e0e071a..7d101a165e 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "pg-monitor": "2.0.0", "pg-promise": "11.3.0", "pluralize": "8.0.0", + "rate-limit-redis": "3.0.1", "redis": "4.0.6", "semver": "7.3.8", "subscriptions-transport-ws": "0.11.0", diff --git a/spec/RateLimit.spec.js b/spec/RateLimit.spec.js index 10bc127719..894c8fcf82 100644 --- a/spec/RateLimit.spec.js +++ b/spec/RateLimit.spec.js @@ -1,3 +1,4 @@ +const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default; describe('rate limit', () => { it('can limit cloud functions', async () => { Parse.Cloud.define('test', () => 'Abc'); @@ -388,4 +389,33 @@ describe('rate limit', () => { }) ).toBeRejectedWith(`Invalid rate limit option "path"`); }); + describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; + })('with RedisCache', function () { + it('does work with cache', async () => { + await reconfigureServer({ + rateLimit: [ + { + requestPath: '/classes/*', + requestTimeWindow: 10000, + requestCount: 1, + errorResponseMessage: 'Too many requests', + includeInternalRequests: true, + redisUrl: 'redis://localhost:6379', + }, + ], + }); + const obj = new Parse.Object('Test'); + await obj.save(); + await expectAsync(obj.save()).toBeRejectedWith( + new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests') + ); + const cache = new RedisCacheAdapter(); + await cache.connect(); + const value = await cache.get('rl:127.0.0.1'); + expect(value).toEqual(2); + const ttl = await cache.client.ttl('rl:127.0.0.1'); + expect(ttl).toEqual(10); + }); + }); }); diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index a25e69c70a..b2f0542256 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -557,6 +557,11 @@ module.exports.RateLimitOptions = { action: parsers.booleanParser, default: false, }, + redisUrl: { + env: 'PARSE_SERVER_RATE_LIMIT_REDIS_URL', + help: + 'Optional, the URL of the Redis server to store rate limit data. This allows to rate limit requests for multiple servers by calculating the sum of all requests across all servers. This is useful if multiple servers are processing requests behind a load balancer. For example, the limit of 10 requests is reached if each of 2 servers processed 5 requests.', + }, requestCount: { env: 'PARSE_SERVER_RATE_LIMIT_REQUEST_COUNT', help: diff --git a/src/Options/docs.js b/src/Options/docs.js index 0eb6488c74..1ab8c03d58 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -104,6 +104,7 @@ * @property {String} errorResponseMessage The error message that should be returned in the body of the HTTP 429 response when the rate limit is hit. Default is `Too many requests.`. * @property {Boolean} includeInternalRequests Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks. * @property {Boolean} includeMasterKey Optional, if `true` the rate limit will also apply to requests using the `masterKey`, default is `false`. Note that a public Cloud Code function that triggers internal requests using the `masterKey` may circumvent rate limiting and be vulnerable to attacks. + * @property {String} redisUrl Optional, the URL of the Redis server to store rate limit data. This allows to rate limit requests for multiple servers by calculating the sum of all requests across all servers. This is useful if multiple servers are processing requests behind a load balancer. For example, the limit of 10 requests is reached if each of 2 servers processed 5 requests. * @property {Number} requestCount The number of requests that can be made per IP address within the time window set in `requestTimeWindow` before the rate limit is applied. * @property {String[]} requestMethods Optional, the HTTP request methods to which the rate limit should be applied, default is all methods. * @property {String} requestPath The path of the API route to be rate limited. Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expression. See: https://expressjs.com/en/guide/routing.html diff --git a/src/Options/index.js b/src/Options/index.js index 778374e7e7..a4d83f94fc 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -320,6 +320,9 @@ export interface RateLimitOptions { /* Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks. :DEFAULT: false */ includeInternalRequests: ?boolean; + /* Optional, the URL of the Redis server to store rate limit data. This allows to rate limit requests for multiple servers by calculating the sum of all requests across all servers. This is useful if multiple servers are processing requests behind a load balancer. For example, the limit of 10 requests is reached if each of 2 servers processed 5 requests. + */ + redisUrl: ?string; } export interface SecurityOptions { diff --git a/src/middlewares.js b/src/middlewares.js index 788c9a3f62..8f3915e4b6 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -11,6 +11,8 @@ 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'; 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'; @@ -476,6 +478,35 @@ export const addRateLimit = (route, config) => { if (!config.rateLimits) { config.rateLimits = []; } + const redisStore = { + connectionPromise: Promise.resolve(), + store: null, + connected: false, + }; + if (route.redisrUrl) { + const client = createClient({ + url: route.redisrUrl, + }); + redisStore.connectionPromise = async () => { + if (redisStore.connected) { + return; + } + try { + await client.connect(); + redisStore.connected = true; + } catch (e) { + const log = config?.loggerController || defaultLogger; + log.error(`Could not connect to redisURL in rate limit: ${e}`); + } + }; + redisStore.connectionPromise(); + redisStore.store = new RedisStore({ + sendCommand: async (...args) => { + await redisStore.connectionPromise(); + return client.sendCommand(args); + }, + }); + } config.rateLimits.push({ path: pathToRegexp(route.requestPath), handler: rateLimit({ @@ -512,6 +543,7 @@ export const addRateLimit = (route, config) => { keyGenerator: request => { return request.config.ip; }, + store: redisStore.store, }), }); Config.put(config); From c4ce59cbd11515a4c96393dd200f63ded7419b50 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Mar 2023 16:44:46 +0000 Subject: [PATCH 13/21] chore(release): 6.1.0-alpha.6 [skip ci] # [6.1.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.5...6.1.0-alpha.6) (2023-03-06) ### Features * Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6)) --- 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 c1062d350b..097f9b3b75 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.5...6.1.0-alpha.6) (2023-03-06) + + +### Features + +* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6)) + # [6.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.4...6.1.0-alpha.5) (2023-03-06) diff --git a/package-lock.json b/package-lock.json index e97746c926..02f90cfdf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.5", + "version": "6.1.0-alpha.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.5", + "version": "6.1.0-alpha.6", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 7d101a165e..46d34297ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.5", + "version": "6.1.0-alpha.6", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 11 Mar 2023 03:43:37 +1100 Subject: [PATCH 14/21] fix: Rate limiting across multiple servers via Redis not working (#8469) --- src/middlewares.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middlewares.js b/src/middlewares.js index 8f3915e4b6..7d0b7fa8f4 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -483,9 +483,9 @@ export const addRateLimit = (route, config) => { store: null, connected: false, }; - if (route.redisrUrl) { + if (route.redisUrl) { const client = createClient({ - url: route.redisrUrl, + url: route.redisUrl, }); redisStore.connectionPromise = async () => { if (redisStore.connected) { From cf1b59e97ba288746f903d282d7b71044f2687d2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 10 Mar 2023 16:44:46 +0000 Subject: [PATCH 15/21] chore(release): 6.1.0-alpha.7 [skip ci] # [6.1.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.6...6.1.0-alpha.7) (2023-03-10) ### Bug Fixes * Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0)) --- 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 097f9b3b75..607bf4cbaf 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.6...6.1.0-alpha.7) (2023-03-10) + + +### Bug Fixes + +* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0)) + # [6.1.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.5...6.1.0-alpha.6) (2023-03-06) diff --git a/package-lock.json b/package-lock.json index 02f90cfdf9..18f5a16b4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.6", + "version": "6.1.0-alpha.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.6", + "version": "6.1.0-alpha.7", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 46d34297ee..fc2dbe6250 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.6", + "version": "6.1.0-alpha.7", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 65e5879e42cefb4b462c9383af3705d027131242 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 11 Mar 2023 09:54:05 +1100 Subject: [PATCH 16/21] ci: Fix flaky tests (#8468) --- spec/AuthenticationAdaptersV2.spec.js | 2 +- spec/Idempotency.spec.js | 4 ---- spec/ParseLiveQueryRedis.spec.js | 2 ++ spec/ParseLiveQueryServer.spec.js | 1 + spec/helper.js | 5 +++++ spec/index.spec.js | 2 +- src/Config.js | 10 ++++++++++ src/TestUtils.js | 13 ++++++++++--- src/cloud-code/Parse.Cloud.js | 17 ++++++++++++----- src/middlewares.js | 3 ++- 10 files changed, 44 insertions(+), 15 deletions(-) diff --git a/spec/AuthenticationAdaptersV2.spec.js b/spec/AuthenticationAdaptersV2.spec.js index 9507691114..aaa172ea66 100644 --- a/spec/AuthenticationAdaptersV2.spec.js +++ b/spec/AuthenticationAdaptersV2.spec.js @@ -348,7 +348,7 @@ describe('Auth Adapter features', () => { it('should strip out authData if required', async () => { const spy = spyOn(modernAdapter3, 'validateOptions').and.callThrough(); const afterSpy = spyOn(modernAdapter3, 'afterFind').and.callThrough(); - await reconfigureServer({ auth: { modernAdapter3 }, silent: false }); + await reconfigureServer({ auth: { modernAdapter3 } }); const user = new Parse.User(); await user.save({ authData: { modernAdapter3: { id: 'modernAdapter3Data' } } }); await user.fetch({ sessionToken: user.getSessionToken() }); diff --git a/spec/Idempotency.spec.js b/spec/Idempotency.spec.js index a45d19343c..813923b1ff 100644 --- a/spec/Idempotency.spec.js +++ b/spec/Idempotency.spec.js @@ -45,10 +45,6 @@ describe('Idempotency', () => { }); }); - afterAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000; - }); - // Tests it('should enforce idempotency for cloud code function', async () => { let counter = 0; diff --git a/spec/ParseLiveQueryRedis.spec.js b/spec/ParseLiveQueryRedis.spec.js index 3187d23cc8..deb84bafb2 100644 --- a/spec/ParseLiveQueryRedis.spec.js +++ b/spec/ParseLiveQueryRedis.spec.js @@ -6,6 +6,7 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') { }); it('can connect', async () => { await reconfigureServer({ + appId: 'redis_live_query', startLiveQueryServer: true, liveQuery: { classNames: ['TestObject'], @@ -36,6 +37,7 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') { it('can call connect twice', async () => { const server = await reconfigureServer({ + appId: 'redis_live_query', startLiveQueryServer: true, liveQuery: { classNames: ['TestObject'], diff --git a/spec/ParseLiveQueryServer.spec.js b/spec/ParseLiveQueryServer.spec.js index 16654cdd64..50f29d0aab 100644 --- a/spec/ParseLiveQueryServer.spec.js +++ b/spec/ParseLiveQueryServer.spec.js @@ -115,6 +115,7 @@ describe('ParseLiveQueryServer', function () { }); describe_only_db('mongo')('initialization', () => { + beforeEach(() => reconfigureServer({ appId: 'mongo_init_test' })); it('can be initialized through ParseServer without liveQueryServerOptions', async () => { const parseServer = await ParseServer.startApp({ appId: 'hello', diff --git a/spec/helper.js b/spec/helper.js index 445a137ac5..445de26509 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -198,6 +198,10 @@ beforeAll(async () => { Parse.serverURL = 'http://localhost:' + port + '/1'; }); +beforeEach(() => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000; +}); + afterEach(function (done) { const afterLogOut = async () => { if (Object.keys(openConnections).length > 0) { @@ -214,6 +218,7 @@ afterEach(function (done) { done(); }; Parse.Cloud._removeAllHooks(); + Parse.CoreManager.getLiveQueryController().setDefaultLiveQueryClient(); defaults.protectedFields = { _User: { '*': ['email'] } }; databaseAdapter .getAllClasses() diff --git a/spec/index.spec.js b/spec/index.spec.js index 64c4b54db7..08ef16a77b 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -558,7 +558,7 @@ describe('server', () => { }); it('can get starting state', async () => { - await reconfigureServer({ appId: 'test2', silent: false }); + await reconfigureServer({ appId: 'test2' }); const parseServer = new ParseServer.ParseServer({ ...defaultConfiguration, appId: 'test2', diff --git a/src/Config.js b/src/Config.js index 2e7ef389c7..812d28c367 100644 --- a/src/Config.js +++ b/src/Config.js @@ -626,6 +626,16 @@ export class Config { return new Date(now.getTime() + this.sessionLength * 1000); } + unregisterRateLimiters() { + let i = this.rateLimits?.length; + while (i--) { + const limit = this.rateLimits[i]; + if (limit.cloud) { + this.rateLimits.splice(i, 1); + } + } + } + get invalidLinkURL() { return this.customPages.invalidLink || `${this.publicServerURL}/apps/invalid_link.html`; } diff --git a/src/TestUtils.js b/src/TestUtils.js index 7772bcd65b..3d5133556d 100644 --- a/src/TestUtils.js +++ b/src/TestUtils.js @@ -1,4 +1,5 @@ import AppCache from './cache'; +import SchemaCache from './Adapters/Cache/SchemaCache'; /** * Destroys all data in the database @@ -11,11 +12,17 @@ export function destroyAllDataPermanently(fast) { return Promise.all( Object.keys(AppCache.cache).map(appId => { const app = AppCache.get(appId); + const deletePromises = []; + if (app.cacheAdapter) { + deletePromises.push(app.cacheAdapter.clear()); + } if (app.databaseController) { - return app.databaseController.deleteEverything(fast); - } else { - return Promise.resolve(); + deletePromises.push(app.databaseController.deleteEverything(fast)); + } else if (app.databaseAdapter) { + SchemaCache.clear(); + deletePromises.push(app.databaseAdapter.deleteAllClasses(fast)); } + return Promise.all(deletePromises); }) ); } diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index 75faf44f3d..5540e8d719 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -128,7 +128,8 @@ ParseCloud.define = function (functionName, handler, validationHandler) { if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: `/functions/${functionName}`, ...validationHandler.rateLimit }, - Parse.applicationId + Parse.applicationId, + true ); } }; @@ -191,7 +192,8 @@ ParseCloud.beforeSave = function (parseClass, handler, validationHandler) { requestMethods: ['POST', 'PUT'], ...validationHandler.rateLimit, }, - Parse.applicationId + Parse.applicationId, + true ); } }; @@ -237,7 +239,8 @@ ParseCloud.beforeDelete = function (parseClass, handler, validationHandler) { requestMethods: 'DELETE', ...validationHandler.rateLimit, }, - Parse.applicationId + Parse.applicationId, + true ); } }; @@ -278,7 +281,8 @@ ParseCloud.beforeLogin = function (handler, validationHandler) { if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: `/login`, requestMethods: 'POST', ...validationHandler.rateLimit }, - Parse.applicationId + Parse.applicationId, + true ); } }; @@ -456,7 +460,8 @@ ParseCloud.beforeFind = function (parseClass, handler, validationHandler) { requestMethods: 'GET', ...validationHandler.rateLimit, }, - Parse.applicationId + Parse.applicationId, + true ); } }; @@ -761,6 +766,8 @@ ParseCloud.afterLiveQueryEvent = function (parseClass, handler, validationHandle ParseCloud._removeAllHooks = () => { triggers._unregisterAll(); + const config = Config.get(Parse.applicationId); + config?.unregisterRateLimiters(); }; ParseCloud.useMasterKey = () => { diff --git a/src/middlewares.js b/src/middlewares.js index 7d0b7fa8f4..0dca33135e 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -466,7 +466,7 @@ export function promiseEnforceMasterKeyAccess(request) { return Promise.resolve(); } -export const addRateLimit = (route, config) => { +export const addRateLimit = (route, config, cloud) => { if (typeof config === 'string') { config = Config.get(config); } @@ -545,6 +545,7 @@ export const addRateLimit = (route, config) => { }, store: redisStore.store, }), + cloud, }); Config.put(config); }; From 177891ea0eed54eff996d81749cfbfb32156ae87 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 11 Apr 2023 17:50:29 +1000 Subject: [PATCH 17/21] ci: Fix check definitions CI job not running (#8503) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a4c267503..dc27805e5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,7 @@ jobs: check-definitions: name: Check Definitions timeout-minutes: 5 - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.NODE_VERSION }} From 9e43bc2fa07ff860d4812df0bec1bb569c5d7e7e Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Sat, 29 Apr 2023 16:53:54 +0200 Subject: [PATCH 18/21] docs: Change API docs template to jsdoc-clean-theme (#8519) --- jsdoc-conf.json | 27 +- package-lock.json | 369 ++++++++++++++++-- package.json | 2 +- src/Adapters/Analytics/AnalyticsAdapter.js | 4 +- src/Adapters/Cache/CacheAdapter.js | 6 +- src/Adapters/Email/MailAdapter.js | 6 +- src/Adapters/Files/FilesAdapter.js | 6 +- src/Adapters/Logger/LoggerAdapter.js | 6 +- src/Adapters/PubSub/PubSubAdapter.js | 6 +- src/Adapters/Push/PushAdapter.js | 6 +- src/Adapters/WebSocketServer/WSSAdapter.js | 6 +- src/Security/Check.js | 2 +- src/Security/CheckGroup.js | 7 +- .../CheckGroups/CheckGroupDatabase.js | 7 +- .../CheckGroups/CheckGroupServerConfig.js | 5 +- src/Security/CheckGroups/CheckGroups.js | 2 +- src/Security/CheckRunner.js | 5 +- 17 files changed, 393 insertions(+), 79 deletions(-) diff --git a/jsdoc-conf.json b/jsdoc-conf.json index ad059acda1..efbaa0a37c 100644 --- a/jsdoc-conf.json +++ b/jsdoc-conf.json @@ -1,10 +1,16 @@ { "plugins": ["node_modules/jsdoc-babel", "plugins/markdown"], "babel": { - "plugins": ["@babel/plugin-transform-flow-strip-types"] + "plugins": ["@babel/plugin-transform-flow-strip-types"] }, "source": { - "include": ["./README.md", "./src/cloud-code", "./src/Options/docs.js", "./src/ParseServer.js", "./src/Adapters"], + "include": [ + "README.md", + "./src/cloud-code", + "./src/Options/docs.js", + "./src/ParseServer.js", + "./src/Adapters" + ], "excludePattern": "(^|\\/|\\\\)_" }, "templates": { @@ -17,7 +23,18 @@ "monospaceLinks": false }, "opts": { - "template": "node_modules/@parse/minami", - "recurse": true + "encoding": "utf8", + "readme": "./README.md", + "recurse": true, + "template": "./node_modules/clean-jsdoc-theme", + "theme_opts": { + "default_theme": "dark", + "title": "", + "create_style": "header, .sidebar-section-title, .sidebar-title { color: #139cee !important } .logo { margin-left : 40px; margin-right: 40px }" + } + }, + "markdown": { + "hardwrap": false, + "idInHeadings": true } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 18f5a16b4e..3041db4ac9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,6 @@ "@babel/plugin-proposal-object-rest-spread": "7.10.0", "@babel/plugin-transform-flow-strip-types": "7.9.0", "@babel/preset-env": "7.10.0", - "@parse/minami": "1.0.0", "@saithodev/semantic-release-backmerge": "2.1.2", "@semantic-release/changelog": "5.0.1", "@semantic-release/commit-analyzer": "8.0.1", @@ -76,6 +75,7 @@ "all-node-versions": "11.3.0", "apollo-upload-client": "17.0.0", "bcrypt-nodejs": "0.0.3", + "clean-jsdoc-theme": "^4.2.7", "cross-env": "7.0.2", "deep-diff": "1.0.2", "eslint": "8.26.0", @@ -595,9 +595,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2288,6 +2288,18 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@jsdoc/salty": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", + "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, "node_modules/@napi-rs/triples": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz", @@ -2746,12 +2758,6 @@ "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.2.tgz", "integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g==" }, - "node_modules/@parse/minami": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@parse/minami/-/minami-1.0.0.tgz", - "integrity": "sha512-Rw+p0WdOOypFPVJsmhyiI+Q056ZxdP2iAtObnU1DZrsvKZTf5x0B/0SjIt0hUgWp+COjqi/p17VdBU9IAD/NJg==", - "dev": true - }, "node_modules/@parse/node-apn": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz", @@ -4687,6 +4693,16 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -4859,6 +4875,59 @@ "node": ">=0.10.0" } }, + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-jsdoc-theme": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/clean-jsdoc-theme/-/clean-jsdoc-theme-4.2.7.tgz", + "integrity": "sha512-yLLxwTFw7N9/toUCcFmKkwJmv4LO2pQWYNETcU3Vv+n2al2L2ohb7xWoXLjp5m3OljC9b1m+o4adzY0YH6Ep4A==", + "dev": true, + "dependencies": { + "@jsdoc/salty": "^0.2.4", + "fs-extra": "^10.1.0", + "html-minifier": "^4.0.0", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "nanoid": "^3.3.4", + "showdown": "^2.1.0" + }, + "peerDependencies": { + "jsdoc": ">=3.x <=4.x" + } + }, + "node_modules/clean-jsdoc-theme/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -8719,6 +8788,15 @@ "node": ">=8" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -8767,6 +8845,33 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/html-minifier/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/htmlparser2": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", @@ -10121,6 +10226,15 @@ "graceful-fs": "^4.1.9" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -10886,6 +11000,12 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, "node_modules/lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -12228,6 +12348,15 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, "node_modules/node-abort-controller": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", @@ -15902,6 +16031,15 @@ "node": ">= 4.0.0" } }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -17320,6 +17458,15 @@ "jsesc": "bin/jsesc" } }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -18163,6 +18310,31 @@ "node": ">=8" } }, + "node_modules/showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "dev": true, + "dependencies": { + "commander": "^9.0.0" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/tiviesantos" + } + }, + "node_modules/showdown/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -19622,7 +19794,6 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, - "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -19848,6 +20019,12 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -20822,9 +20999,9 @@ } }, "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" }, "@babel/plugin-proposal-object-rest-spread": { "version": "7.10.0", @@ -22033,6 +22210,15 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@jsdoc/salty": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", + "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, "@napi-rs/triples": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz", @@ -22359,12 +22545,6 @@ "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.2.tgz", "integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g==" }, - "@parse/minami": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@parse/minami/-/minami-1.0.0.tgz", - "integrity": "sha512-Rw+p0WdOOypFPVJsmhyiI+Q056ZxdP2iAtObnU1DZrsvKZTf5x0B/0SjIt0hUgWp+COjqi/p17VdBU9IAD/NJg==", - "dev": true - }, "@parse/node-apn": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz", @@ -23877,6 +24057,16 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -24009,6 +24199,51 @@ "static-extend": "^0.1.1" } }, + "clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "clean-jsdoc-theme": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/clean-jsdoc-theme/-/clean-jsdoc-theme-4.2.7.tgz", + "integrity": "sha512-yLLxwTFw7N9/toUCcFmKkwJmv4LO2pQWYNETcU3Vv+n2al2L2ohb7xWoXLjp5m3OljC9b1m+o4adzY0YH6Ep4A==", + "dev": true, + "requires": { + "@jsdoc/salty": "^0.2.4", + "fs-extra": "^10.1.0", + "html-minifier": "^4.0.0", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "nanoid": "^3.3.4", + "showdown": "^2.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -27001,6 +27236,12 @@ } } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -27042,6 +27283,29 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, "htmlparser2": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", @@ -28086,6 +28350,15 @@ "graceful-fs": "^4.1.9" } }, + "klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11" + } + }, "kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -28705,6 +28978,12 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, "lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -29767,6 +30046,15 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, "node-abort-controller": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", @@ -32419,6 +32707,15 @@ "wcwidth": "^1.0.1" } }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -33509,6 +33806,12 @@ } } }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true + }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -34148,6 +34451,23 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, + "showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "dev": true, + "requires": { + "commander": "^9.0.0" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true + } + } + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -35306,8 +35626,7 @@ "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true + "dev": true }, "unbzip2-stream": { "version": "1.4.3", @@ -35469,6 +35788,12 @@ "picocolors": "^1.0.0" } }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index fc2dbe6250..8c81750838 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "@babel/plugin-proposal-object-rest-spread": "7.10.0", "@babel/plugin-transform-flow-strip-types": "7.9.0", "@babel/preset-env": "7.10.0", - "@parse/minami": "1.0.0", "@saithodev/semantic-release-backmerge": "2.1.2", "@semantic-release/changelog": "5.0.1", "@semantic-release/commit-analyzer": "8.0.1", @@ -82,6 +81,7 @@ "all-node-versions": "11.3.0", "apollo-upload-client": "17.0.0", "bcrypt-nodejs": "0.0.3", + "clean-jsdoc-theme": "4.2.7", "cross-env": "7.0.2", "deep-diff": "1.0.2", "eslint": "8.26.0", diff --git a/src/Adapters/Analytics/AnalyticsAdapter.js b/src/Adapters/Analytics/AnalyticsAdapter.js index 3fd50242d9..e3cced14f5 100644 --- a/src/Adapters/Analytics/AnalyticsAdapter.js +++ b/src/Adapters/Analytics/AnalyticsAdapter.js @@ -1,9 +1,7 @@ /*eslint no-unused-vars: "off"*/ -/** - * @module Adapters - */ /** * @interface AnalyticsAdapter + * @module Adapters */ export class AnalyticsAdapter { /** diff --git a/src/Adapters/Cache/CacheAdapter.js b/src/Adapters/Cache/CacheAdapter.js index 224d0c006e..7632797e55 100644 --- a/src/Adapters/Cache/CacheAdapter.js +++ b/src/Adapters/Cache/CacheAdapter.js @@ -1,9 +1,7 @@ /*eslint no-unused-vars: "off"*/ /** - * @module Adapters - */ -/** - * @interface CacheAdapter + * @interface + * @memberof module:Adapters */ export class CacheAdapter { /** diff --git a/src/Adapters/Email/MailAdapter.js b/src/Adapters/Email/MailAdapter.js index 791f9e6bd4..93069e2c27 100644 --- a/src/Adapters/Email/MailAdapter.js +++ b/src/Adapters/Email/MailAdapter.js @@ -1,9 +1,7 @@ /*eslint no-unused-vars: "off"*/ /** - * @module Adapters - */ -/** - * @interface MailAdapter + * @interface + * @memberof module:Adapters * Mail Adapter prototype * A MailAdapter should implement at least sendMail() */ diff --git a/src/Adapters/Files/FilesAdapter.js b/src/Adapters/Files/FilesAdapter.js index 68666b919a..afd06942e9 100644 --- a/src/Adapters/Files/FilesAdapter.js +++ b/src/Adapters/Files/FilesAdapter.js @@ -19,10 +19,8 @@ import type { Config } from '../../Config'; import Parse from 'parse/node'; /** - * @module Adapters - */ -/** - * @interface FilesAdapter + * @interface + * @memberof module:Adapters */ export class FilesAdapter { /** Responsible for storing the file in order to be retrieved later by its filename diff --git a/src/Adapters/Logger/LoggerAdapter.js b/src/Adapters/Logger/LoggerAdapter.js index 21df5ccd48..3853d5f480 100644 --- a/src/Adapters/Logger/LoggerAdapter.js +++ b/src/Adapters/Logger/LoggerAdapter.js @@ -1,9 +1,7 @@ /*eslint no-unused-vars: "off"*/ /** - * @module Adapters - */ -/** - * @interface LoggerAdapter + * @interface + * @memberof module:Adapters * Logger Adapter * Allows you to change the logger mechanism * Default is WinstonLoggerAdapter.js diff --git a/src/Adapters/PubSub/PubSubAdapter.js b/src/Adapters/PubSub/PubSubAdapter.js index 9e6b13dfc7..728dff90e8 100644 --- a/src/Adapters/PubSub/PubSubAdapter.js +++ b/src/Adapters/PubSub/PubSubAdapter.js @@ -1,9 +1,7 @@ /*eslint no-unused-vars: "off"*/ /** - * @module Adapters - */ -/** - * @interface PubSubAdapter + * @interface + * @memberof module:Adapters */ export class PubSubAdapter { /** diff --git a/src/Adapters/Push/PushAdapter.js b/src/Adapters/Push/PushAdapter.js index 191fa15b40..fb0adbf469 100644 --- a/src/Adapters/Push/PushAdapter.js +++ b/src/Adapters/Push/PushAdapter.js @@ -12,10 +12,8 @@ // android push and APNS for ios push. /** - * @module Adapters - */ -/** - * @interface PushAdapter + * @interface + * @memberof module:Adapters */ export class PushAdapter { /** diff --git a/src/Adapters/WebSocketServer/WSSAdapter.js b/src/Adapters/WebSocketServer/WSSAdapter.js index 007cacdf76..a810c03f9d 100644 --- a/src/Adapters/WebSocketServer/WSSAdapter.js +++ b/src/Adapters/WebSocketServer/WSSAdapter.js @@ -11,10 +11,8 @@ // Default is WSAdapter. The above functions will be binded. /** - * @module Adapters - */ -/** - * @interface WSSAdapter + * @interface + * @memberof module:Adapters */ export class WSSAdapter { /** diff --git a/src/Security/Check.js b/src/Security/Check.js index dc57d63088..c31480e73d 100644 --- a/src/Security/Check.js +++ b/src/Security/Check.js @@ -7,7 +7,7 @@ import { isFunction, isString } from 'lodash'; /** * A security check. - * @class Check + * @class */ class Check { /** diff --git a/src/Security/CheckGroup.js b/src/Security/CheckGroup.js index a9fde2905f..d8e3f8e08e 100644 --- a/src/Security/CheckGroup.js +++ b/src/Security/CheckGroup.js @@ -1,10 +1,7 @@ -/** - * @module SecurityCheck - */ - /** * A group of security checks. - * @interface CheckGroup + * @interface + * @memberof module:SecurityCheck */ class CheckGroup { constructor() { diff --git a/src/Security/CheckGroups/CheckGroupDatabase.js b/src/Security/CheckGroups/CheckGroupDatabase.js index f9b9340eb1..bc57fef8a3 100644 --- a/src/Security/CheckGroups/CheckGroupDatabase.js +++ b/src/Security/CheckGroups/CheckGroupDatabase.js @@ -1,7 +1,3 @@ -/** - * @module SecurityCheck - */ - import { Check } from '../Check'; import CheckGroup from '../CheckGroup'; import Config from '../../Config'; @@ -9,7 +5,8 @@ import Parse from 'parse/node'; /** * The security checks group for Parse Server configuration. - * Checks common Parse Server parameters such as access keys. + * Checks common Parse Server parameters such as access keys + * @memberof module:SecurityCheck */ class CheckGroupDatabase extends CheckGroup { setName() { diff --git a/src/Security/CheckGroups/CheckGroupServerConfig.js b/src/Security/CheckGroups/CheckGroupServerConfig.js index a9c6e671cc..b2b2376cb1 100644 --- a/src/Security/CheckGroups/CheckGroupServerConfig.js +++ b/src/Security/CheckGroups/CheckGroupServerConfig.js @@ -1,7 +1,3 @@ -/** - * @module SecurityCheck - */ - import { Check } from '../Check'; import CheckGroup from '../CheckGroup'; import Config from '../../Config'; @@ -10,6 +6,7 @@ import Parse from 'parse/node'; /** * The security checks group for Parse Server configuration. * Checks common Parse Server parameters such as access keys. + * @memberof module:SecurityCheck */ class CheckGroupServerConfig extends CheckGroup { setName() { diff --git a/src/Security/CheckGroups/CheckGroups.js b/src/Security/CheckGroups/CheckGroups.js index d1c4f03d8c..36f90e019c 100644 --- a/src/Security/CheckGroups/CheckGroups.js +++ b/src/Security/CheckGroups/CheckGroups.js @@ -1,5 +1,5 @@ /** - * @module SecurityCheck + * @memberof module:SecurityCheck */ /** diff --git a/src/Security/CheckRunner.js b/src/Security/CheckRunner.js index a662ffbad4..4be1c3acbf 100644 --- a/src/Security/CheckRunner.js +++ b/src/Security/CheckRunner.js @@ -1,7 +1,3 @@ -/** - * @module SecurityCheck - */ - import Utils from '../Utils'; import { CheckState } from './Check'; import * as CheckGroups from './CheckGroups/CheckGroups'; @@ -10,6 +6,7 @@ import { isArray, isBoolean } from 'lodash'; /** * The security check runner. + * @memberof module:SecurityCheck */ class CheckRunner { /** From 4f15539ac244aa2d393ac5177f7604b43f69e271 Mon Sep 17 00:00:00 2001 From: Marc Derhammer Date: Mon, 1 May 2023 16:25:22 -0400 Subject: [PATCH 19/21] feat: Allow multiple origins for header `Access-Control-Allow-Origin` (#8517) --- resources/buildConfigDefinitions.js | 6 ++++++ spec/Middlewares.spec.js | 29 +++++++++++++++++++++++++++++ src/Options/Definitions.js | 4 +++- src/Options/docs.js | 2 +- src/Options/index.js | 5 +++-- src/middlewares.js | 9 +++++++-- 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index 3a69217016..e0d33daa4b 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -161,6 +161,9 @@ function mapperFor(elt, t) { if (type == 'NumberOrBoolean') { return wrap(t.identifier('numberOrBooleanParser')); } + if (type === 'StringOrStringArray') { + return wrap(t.identifier('arrayParser')); + } return wrap(t.identifier('objectParser')); } } @@ -278,6 +281,9 @@ function inject(t, list) { const adapterType = elt.typeAnnotation.typeParameters.params[0].id.name; type = `Adapter<${adapterType}>`; } + if (type === 'StringOrStringArray') { + type = 'String|String[]'; + } comments += ` * @property {${type}} ${elt.name} ${elt.help}\n`; const obj = t.objectExpression(props); return t.objectProperty(t.stringLiteral(elt.name), obj); diff --git a/spec/Middlewares.spec.js b/spec/Middlewares.spec.js index 12bfc59bf7..636e7809f9 100644 --- a/spec/Middlewares.spec.js +++ b/spec/Middlewares.spec.js @@ -287,6 +287,35 @@ describe('middlewares', () => { expect(headers['Access-Control-Allow-Origin']).toEqual('https://parseplatform.org/'); }); + it('should support multiple origins if several are defined in allowOrigin as an array', () => { + AppCache.put(fakeReq.body._ApplicationId, { + allowOrigin: ['https://a.com', 'https://b.com', 'https://c.com'], + }); + const headers = {}; + const res = { + header: (key, value) => { + headers[key] = value; + }, + }; + const allowCrossDomain = middlewares.allowCrossDomain(fakeReq.body._ApplicationId); + // Test with the first domain + fakeReq.headers.origin = 'https://a.com'; + allowCrossDomain(fakeReq, res, () => {}); + expect(headers['Access-Control-Allow-Origin']).toEqual('https://a.com'); + // Test with the second domain + fakeReq.headers.origin = 'https://b.com'; + allowCrossDomain(fakeReq, res, () => {}); + expect(headers['Access-Control-Allow-Origin']).toEqual('https://b.com'); + // Test with the third domain + fakeReq.headers.origin = 'https://c.com'; + allowCrossDomain(fakeReq, res, () => {}); + expect(headers['Access-Control-Allow-Origin']).toEqual('https://c.com'); + // Test with an unauthorized domain + fakeReq.headers.origin = 'https://unauthorized.com'; + allowCrossDomain(fakeReq, res, () => {}); + expect(headers['Access-Control-Allow-Origin']).toEqual('https://a.com'); + }); + it('should use user provided on field userFromJWT', done => { AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index b2f0542256..7987363ff2 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -81,7 +81,9 @@ module.exports.ParseServerOptions = { }, allowOrigin: { env: 'PARSE_SERVER_ALLOW_ORIGIN', - help: 'Sets the origin to Access-Control-Allow-Origin', + help: + 'Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins.', + action: parsers.arrayParser, }, analyticsAdapter: { env: 'PARSE_SERVER_ANALYTICS_ADAPTER', diff --git a/src/Options/docs.js b/src/Options/docs.js index 1ab8c03d58..b5a78aace1 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -16,7 +16,7 @@ * @property {Boolean} allowCustomObjectId Enable (or disable) custom objectId * @property {Boolean} allowExpiredAuthDataToken Allow a user to log in even if the 3rd party authentication token that was used to sign in to their account has expired. If this is set to `false`, then the token will be validated every time the user signs in to their account. This refers to the token that is stored in the `_User.authData` field. Defaults to `true`. * @property {String[]} allowHeaders Add headers to Access-Control-Allow-Headers - * @property {String} allowOrigin Sets the origin to Access-Control-Allow-Origin + * @property {String|String[]} allowOrigin Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins. * @property {Adapter} analyticsAdapter Adapter module for the analytics * @property {String} appId Your Parse Application ID * @property {String} appName Sets the app name diff --git a/src/Options/index.js b/src/Options/index.js index a4d83f94fc..009b31a5d5 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -35,6 +35,7 @@ type Adapter = string | any | T; type NumberOrBoolean = number | boolean; type NumberOrString = number | string; type ProtectedFields = any; +type StringOrStringArray = string | string[]; type RequestKeywordDenylist = { key: string | any, value: any, @@ -61,8 +62,8 @@ export interface ParseServerOptions { appName: ?string; /* Add headers to Access-Control-Allow-Headers */ allowHeaders: ?(string[]); - /* Sets the origin to Access-Control-Allow-Origin */ - allowOrigin: ?string; + /* Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins. */ + allowOrigin: ?StringOrStringArray; /* Adapter module for the analytics */ analyticsAdapter: ?Adapter; /* Adapter module for the files sub-system */ diff --git a/src/middlewares.js b/src/middlewares.js index 0dca33135e..2e450f3e03 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -384,8 +384,13 @@ export function allowCrossDomain(appId) { if (config && config.allowHeaders) { allowHeaders += `, ${config.allowHeaders.join(', ')}`; } - const allowOrigin = (config && config.allowOrigin) || '*'; - res.header('Access-Control-Allow-Origin', allowOrigin); + + const baseOrigins = + typeof config?.allowOrigin === 'string' ? [config.allowOrigin] : config?.allowOrigin ?? ['*']; + const requestOrigin = req.headers.origin; + const allowOrigins = + requestOrigin && baseOrigins.includes(requestOrigin) ? requestOrigin : baseOrigins[0]; + res.header('Access-Control-Allow-Origin', allowOrigins); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', allowHeaders); res.header('Access-Control-Expose-Headers', 'X-Parse-Job-Status-Id, X-Parse-Push-Status-Id'); From 2f53c80298c5de85c09b6e84c3dd71fdfd6cbeb6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 1 May 2023 20:26:26 +0000 Subject: [PATCH 20/21] chore(release): 6.1.0-alpha.8 [skip ci] # [6.1.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.7...6.1.0-alpha.8) (2023-05-01) ### Features * Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271)) --- 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 607bf4cbaf..a2b4c268d6 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [6.1.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.7...6.1.0-alpha.8) (2023-05-01) + + +### Features + +* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271)) + # [6.1.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.6...6.1.0-alpha.7) (2023-03-10) diff --git a/package-lock.json b/package-lock.json index 3041db4ac9..ae752fdb36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "6.1.0-alpha.7", + "version": "6.1.0-alpha.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "6.1.0-alpha.7", + "version": "6.1.0-alpha.8", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 8c81750838..cca14c5643 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "6.1.0-alpha.7", + "version": "6.1.0-alpha.8", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 2e4119e23d5c7ad1e5e4934691c610a5a3fd0a29 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Mon, 1 May 2023 23:16:57 +0200 Subject: [PATCH 21/21] ci: Fix auto-release outdated ubuntu version (#8524) --- .github/workflows/release-automated.yml | 4 ++-- .github/workflows/release-manual-docker.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-automated.yml b/.github/workflows/release-automated.yml index 9c4a6c6896..271d4abca3 100644 --- a/.github/workflows/release-automated.yml +++ b/.github/workflows/release-automated.yml @@ -42,7 +42,7 @@ jobs: env: REGISTRY: docker.io IMAGE_NAME: parseplatform/parse-server - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest permissions: contents: read packages: write @@ -86,7 +86,7 @@ jobs: docs: needs: release if: needs.release.outputs.current_tag != '' && github.ref == 'refs/heads/release' - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/release-manual-docker.yml b/.github/workflows/release-manual-docker.yml index 3300f2a498..1d19189c3a 100644 --- a/.github/workflows/release-manual-docker.yml +++ b/.github/workflows/release-manual-docker.yml @@ -14,7 +14,7 @@ env: IMAGE_NAME: parseplatform/parse-server jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest permissions: contents: read packages: write