From b6a66761f049ce5c9fe0a83d755c85e7da284439 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Mon, 1 Nov 2021 17:28:37 +0100 Subject: [PATCH 01/83] docs: enable badge and changelog for beta release --- CHANGELOG.md | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a977705686..7c12e7cf72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ Details: - Purpose: official release - Suitable environment: production - +- Suitable environment: development ## 🔥 [Alpha Releases][log_alpha] diff --git a/README.md b/README.md index a25752cc6e..5bd803355f 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ [![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases) [![npm latest version](https://img.shields.io/npm/v/parse-server/latest.svg)](https://www.npmjs.com/package/parse-server) +[![npm beta version](https://img.shields.io/npm/v/parse-server/beta.svg)](https://www.npmjs.com/package/parse-server) [![npm alpha version](https://img.shields.io/npm/v/parse-server/alpha.svg)](https://www.npmjs.com/package/parse-server) - [![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)][open-collective-link] [![Sponsors on Open Collective](https://opencollective.com/parse-server/sponsors/badge.svg)][open-collective-link] From 69fd494ab2198cb97eed0e432ca0f13b5f972290 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 3 Nov 2021 23:03:13 +0100 Subject: [PATCH 02/83] docs: add bronze sponsor and add sponsor widgets to README --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5bd803355f..f787ab632d 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ [![Build Status](https://github.com/parse-community/parse-server/workflows/ci/badge.svg?branch=alpha)](https://github.com/parse-community/parse-server/actions?query=workflow%3Aci+branch%3Aalpha) [![Snyk Badge](https://snyk.io/test/github/parse-community/parse-server/badge.svg)](https://snyk.io/test/github/parse-community/parse-server) [![Coverage](https://img.shields.io/codecov/c/github/parse-community/parse-server/alpha.svg)](https://codecov.io/github/parse-community/parse-server?branch=alpha) +[![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases) [![Node Version](https://img.shields.io/badge/nodejs-12,_14,_15-green.svg?logo=node.js&style=flat)](https://nodejs.org) [![MongoDB Version](https://img.shields.io/badge/mongodb-4.0,_4.2,_4.4,_5.0-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com) [![Postgres Version](https://img.shields.io/badge/postgresql-11,_12,_13,_14-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org) -[![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases) [![npm latest version](https://img.shields.io/npm/v/parse-server/latest.svg)](https://www.npmjs.com/package/parse-server) [![npm beta version](https://img.shields.io/npm/v/parse-server/beta.svg)](https://www.npmjs.com/package/parse-server) @@ -29,11 +29,15 @@ The full documentation for Parse Server is available in the [wiki](https://githu --- -A big *thank you* to all our backers and sponsors who support the development of Parse Platform! +A big *thank you* 🙏 to all our backers and sponsors who support the development of Parse Platform! -### 💎 Diamond Sponsors - -[![Sponsor](https://opencollective.com/parse-server/sponsor/0/avatar.svg)](https://opencollective.com/parse-server/sponsor/0/website) +### Diamond Sponsors + +![Diamond Sponsors](https://opencollective.com/parse-server/tiers/diamond-sponsor.svg?avatarHeight=70&button=false) + +#### Bronze Sponsors + +![Bronze Sponsors](https://opencollective.com/parse-server/tiers/bronze-sponsor.svg?avatarHeight=36&button=false) --- From 31960b59b04dac5ea967118d6fc3f49850225289 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 3 Nov 2021 23:44:24 +0100 Subject: [PATCH 03/83] docs: fix sponsor links in readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f787ab632d..77bc0c4750 100644 --- a/README.md +++ b/README.md @@ -29,15 +29,15 @@ The full documentation for Parse Server is available in the [wiki](https://githu --- -A big *thank you* 🙏 to all our backers and sponsors who support the development of Parse Platform! +A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who support the development of Parse Platform! ### Diamond Sponsors -![Diamond Sponsors](https://opencollective.com/parse-server/tiers/diamond-sponsor.svg?avatarHeight=70&button=false) +[![Diamond Sponsors](https://opencollective.com/parse-server/tiers/diamond-sponsor.svg?avatarHeight=70&button=false)](https://opencollective.com/parse-server/contribute/diamond-sponsor-10560) #### Bronze Sponsors -![Bronze Sponsors](https://opencollective.com/parse-server/tiers/bronze-sponsor.svg?avatarHeight=36&button=false) +[![Bronze Sponsors](https://opencollective.com/parse-server/tiers/bronze-sponsor.svg?avatarHeight=36&button=false)](https://opencollective.com/parse-server/contribute/bronze-sponsor-10559) --- From 611bd9baaa29bfa25b5a8592c8465f2572ff3f65 Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 7 Nov 2021 19:30:15 -0500 Subject: [PATCH 04/83] docs: add FS storage to docs (#7681) --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 77bc0c4750..5a8a5d7dcf 100644 --- a/README.md +++ b/README.md @@ -489,11 +489,12 @@ You can also find more adapters maintained by the community by searching on [npm Parse Server allows developers to choose from several options when hosting files: -* `GridFSBucketAdapter`, which is backed by MongoDB; -* `S3Adapter`, which is backed by [Amazon S3](https://aws.amazon.com/s3/); or -* `GCSAdapter`, which is backed by [Google Cloud Storage](https://cloud.google.com/storage/) +* `GridFSBucketAdapter` - which is backed by MongoDB +* `S3Adapter` - which is backed by [Amazon S3](https://aws.amazon.com/s3/) +* `GCSAdapter` - which is backed by [Google Cloud Storage](https://cloud.google.com/storage/) +* `FSAdapter` - local file storage -`GridFSBucketAdapter` is used by default and requires no setup, but if you're interested in using S3 or Google Cloud Storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters). +`GridFSBucketAdapter` is used by default and requires no setup, but if you're interested in using Amazon S3, Google Cloud Storage, or local file storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters). ## Idempotency Enforcement From b64640c5705f733798783e68d216e957044ef23c Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 10 Nov 2021 16:26:20 +0100 Subject: [PATCH 05/83] revert: refactor: allow ES import for cloud string if package type is module This reverts commit 0225340ccbba2781e49689640ded606a8379dd45. --- .babelrc | 3 +-- spec/CloudCode.spec.js | 8 -------- spec/cloud/cloudCodeModuleFile.js | 3 --- src/ParseServer.js | 6 +----- 4 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 spec/cloud/cloudCodeModuleFile.js diff --git a/.babelrc b/.babelrc index a199154b82..9151969bde 100644 --- a/.babelrc +++ b/.babelrc @@ -7,8 +7,7 @@ ["@babel/preset-env", { "targets": { "node": "12" - }, - "exclude": ["proposal-dynamic-import"] + } }] ], "sourceMaps": "inline" diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 17968c33d7..d5e6113763 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -39,14 +39,6 @@ describe('Cloud Code', () => { }); }); - it('can load cloud code as a module', async () => { - process.env.npm_package_type = 'module'; - await reconfigureServer({ cloud: './spec/cloud/cloudCodeModuleFile.js' }); - const result = await Parse.Cloud.run('cloudCodeInFile'); - expect(result).toEqual('It is possible to define cloud code in a file.'); - delete process.env.npm_package_type; - }); - it('can create functions', done => { Parse.Cloud.define('hello', () => { return 'Hello world!'; diff --git a/spec/cloud/cloudCodeModuleFile.js b/spec/cloud/cloudCodeModuleFile.js deleted file mode 100644 index a62b4fcc24..0000000000 --- a/spec/cloud/cloudCodeModuleFile.js +++ /dev/null @@ -1,3 +0,0 @@ -Parse.Cloud.define('cloudCodeInFile', () => { - return 'It is possible to define cloud code in a file.'; -}); diff --git a/src/ParseServer.js b/src/ParseServer.js index dc2af9e7be..e6b30d1918 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -108,11 +108,7 @@ class ParseServer { if (typeof cloud === 'function') { cloud(Parse); } else if (typeof cloud === 'string') { - if (process.env.npm_package_type === 'module') { - import(path.resolve(process.cwd(), cloud)); - } else { - require(path.resolve(process.cwd(), cloud)); - } + require(path.resolve(process.cwd(), cloud)); } else { throw "argument 'cloud' must either be a string or a function"; } From d35eeb825e4aaabeeeb89690dbaafc7047a7e3c7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Nov 2021 15:27:17 +0000 Subject: [PATCH 06/83] chore(release): 5.0.0-alpha.6 [skip ci] # [5.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.5...5.0.0-alpha.6) (2021-11-10) ### Reverts * refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 1d5c4e5ee9..e86a847932 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.5...5.0.0-alpha.6) (2021-11-10) + + +### Reverts + +* refactor: allow ES import for cloud string if package type is module ([b64640c](https://github.com/parse-community/parse-server/commit/b64640c5705f733798783e68d216e957044ef23c)) + # [5.0.0-alpha.5](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.4...5.0.0-alpha.5) (2021-11-01) diff --git a/package-lock.json b/package-lock.json index 6b37705ad4..ef6abb505f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.5", + "version": "5.0.0-alpha.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 23c1981c32..e6fe99098b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.5", + "version": "5.0.0-alpha.6", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 573558d3adcbcc6222c92003829867e1a73eef94 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Fri, 12 Nov 2021 18:37:03 +0100 Subject: [PATCH 07/83] fix: node engine range has no upper limit to exclude incompatible node versions (#7692) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6fe99098b..d9d57d7f26 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "madge:circular": "node_modules/.bin/madge ./src --circular" }, "engines": { - "node": ">=12.20.0" + "node": ">=12.20.0 <16" }, "bin": { "parse-server": "bin/parse-server" From d72717d23a8d34d89fbb2a1593c518466d38ab6d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 12 Nov 2021 17:38:15 +0000 Subject: [PATCH 08/83] chore(release): 5.0.0-alpha.7 [skip ci] # [5.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.6...5.0.0-alpha.7) (2021-11-12) ### Bug Fixes * node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index e86a847932..cd67f72253 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.6...5.0.0-alpha.7) (2021-11-12) + + +### Bug Fixes + +* node engine range has no upper limit to exclude incompatible node versions ([#7692](https://github.com/parse-community/parse-server/issues/7692)) ([573558d](https://github.com/parse-community/parse-server/commit/573558d3adcbcc6222c92003829867e1a73eef94)) + # [5.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.5...5.0.0-alpha.6) (2021-11-10) diff --git a/package-lock.json b/package-lock.json index ef6abb505f..bb8a577fd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.6", + "version": "5.0.0-alpha.7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d9d57d7f26..38147a69bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.6", + "version": "5.0.0-alpha.7", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From e4aa1cb0a0c4c28956d75fc813a752ed6d22a9f2 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sat, 13 Nov 2021 00:47:02 +0100 Subject: [PATCH 09/83] refactor: upgrade follow-redirects from 1.14.2 to 1.14.4 (#7694) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb8a577fd7..b9aa107df8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7070,9 +7070,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz", - "integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==" + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", + "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index 38147a69bb..91424ed84f 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "cors": "2.8.5", "deepcopy": "2.1.0", "express": "4.17.1", - "follow-redirects": "1.14.2", + "follow-redirects": "1.14.4", "graphql": "15.6.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.9.0", From 3d7ed8dfacef0134e25c6090793611f3febcfc19 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sat, 13 Nov 2021 20:11:52 +0100 Subject: [PATCH 10/83] refactor: upgrade @parse/fs-files-adapter from 1.2.0 to 1.2.1 (#7695) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9aa107df8..b228ddd679 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1739,9 +1739,9 @@ } }, "@parse/fs-files-adapter": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.0.tgz", - "integrity": "sha512-kr7Ti2eYOm14p05S86yriJdMtawL6qln3Dn5eekrwY14ih4jrjH/E+QlEpBUSBzN64fluFxciFOyjdbwDGWsGw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.1.tgz", + "integrity": "sha512-jUbmlvql9+5Mz8Q6KSk1jH823MVerhOYK1svayYpF03v75OtDn3p+mAoFvPS5UpRln1kT6BlBnLfw4Hv08SD5Q==" }, "@parse/minami": { "version": "1.0.0", diff --git a/package.json b/package.json index 91424ed84f..8729a01ef6 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@graphql-tools/links": "6.2.5", "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", - "@parse/fs-files-adapter": "1.2.0", + "@parse/fs-files-adapter": "1.2.1", "@parse/push-adapter": "3.4.1", "apollo-server-express": "2.25.2", "bcryptjs": "2.4.3", From a2fefde4bae6969ed443ba22615a0a232495f2cc Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 14 Nov 2021 03:14:01 +0100 Subject: [PATCH 11/83] refactor: upgrade pg-promise from 10.11.0 to 10.11.1 (#7697) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b228ddd679..f96628eaba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13680,9 +13680,9 @@ "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==" }, "pg-promise": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.11.0.tgz", - "integrity": "sha512-UntgHZNv+gpGJKhh+tzGSGHLkniKWV+ZQ8/SNdtvElsg9Aa7ZJ4Fgyl6pl2x0ZtJ7uFNy+OIq3Z+Ei6iplqTDQ==", + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.11.1.tgz", + "integrity": "sha512-HAv32WSKf2m2RqHerW5RmANn/mcXIwWXbg/gOfGQcoS0SE+8iBi3Jj4JmoR4PNzSEozo/y/npy4e6F16psOItw==", "requires": { "assert-options": "0.7.0", "pg": "8.7.1", diff --git a/package.json b/package.json index 8729a01ef6..178a74764b 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "mustache": "4.2.0", "parse": "3.3.1", "pg-monitor": "1.4.1", - "pg-promise": "10.11.0", + "pg-promise": "10.11.1", "pluralize": "8.0.0", "redis": "3.1.2", "semver": "7.3.5", From 426ccdc8f325601da58648f1e9432500dacf809b Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 14 Nov 2021 03:31:05 +0100 Subject: [PATCH 12/83] refactor: upgrade ws from 8.2.2 to 8.2.3 (#7698) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index f96628eaba..a95ba96b47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16820,9 +16820,9 @@ } }, "ws": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.2.tgz", - "integrity": "sha512-Q6B6H2oc8QY3llc3cB8kVmQ6pnJWVQbP7Q5algTcIxx7YEpc0oU4NBVHlztA7Ekzfhw2r0rPducMUiCGWKQRzw==" + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" }, "xmlcreate": { "version": "2.0.3", diff --git a/package.json b/package.json index 178a74764b..7a26b0d87c 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "uuid": "8.3.2", "winston": "3.3.3", "winston-daily-rotate-file": "4.5.5", - "ws": "8.2.2" + "ws": "8.2.3" }, "devDependencies": { "@actions/core": "1.2.6", From 251ff0ef715e12df7c8e3fd6fd742077dab58946 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 14 Nov 2021 04:14:21 +0100 Subject: [PATCH 13/83] refactor: upgrade graphql from 15.6.0 to 15.6.1 (#7696) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index a95ba96b47..0e733e786c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7476,9 +7476,9 @@ "dev": true }, "graphql": { - "version": "15.6.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.6.0.tgz", - "integrity": "sha512-WJR872Zlc9hckiEPhXgyUftXH48jp2EjO5tgBBOyNMRJZ9fviL2mJBD6CAysk6N5S0r9BTs09Qk39nnJBkvOXQ==" + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.6.1.tgz", + "integrity": "sha512-3i5lu0z6dRvJ48QP9kFxBkJ7h4Kso7PS8eahyTFz5Jm6CvQfLtNIE8LX9N6JLnXTuwR+sIYnXzaWp6anOg0QQw==" }, "graphql-extensions": { "version": "0.15.0", diff --git a/package.json b/package.json index 7a26b0d87c..0cd3eb4160 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "deepcopy": "2.1.0", "express": "4.17.1", "follow-redirects": "1.14.4", - "graphql": "15.6.0", + "graphql": "15.6.1", "graphql-list-fields": "2.0.2", "graphql-relay": "0.9.0", "graphql-tag": "2.12.5", From ae99b928092107169f754d9082b598f14e5266cd Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Wed, 17 Nov 2021 13:28:34 +0100 Subject: [PATCH 14/83] refactor: upgrade graphql from 15.6.1 to 15.7.0 (#7704) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e733e786c..9e541d2732 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7476,9 +7476,9 @@ "dev": true }, "graphql": { - "version": "15.6.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.6.1.tgz", - "integrity": "sha512-3i5lu0z6dRvJ48QP9kFxBkJ7h4Kso7PS8eahyTFz5Jm6CvQfLtNIE8LX9N6JLnXTuwR+sIYnXzaWp6anOg0QQw==" + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.7.0.tgz", + "integrity": "sha512-1jvUsS5mSzcgXLTQNQyrP7eKkBZW+HUnmx2LYSnfvkyseVpij8wwO/sFBGgxbkZ+zzFwYQxrHsOana5oMXmMxg==" }, "graphql-extensions": { "version": "0.15.0", diff --git a/package.json b/package.json index 0cd3eb4160..b78ebfb986 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "deepcopy": "2.1.0", "express": "4.17.1", "follow-redirects": "1.14.4", - "graphql": "15.6.1", + "graphql": "15.7.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.9.0", "graphql-tag": "2.12.5", From 45cc58c7e5e640a46c5d508019a3aa81242964b1 Mon Sep 17 00:00:00 2001 From: Marvin ROGER Date: Thu, 18 Nov 2021 23:37:47 +0100 Subject: [PATCH 15/83] feat: add support for Node 16 (#7707) BREAKING CHANGE: Removes official Node 15 support which has reached it end-of-life date. --- .github/workflows/ci.yml | 28 +-- README.md | 3 +- ci/ciCheck.js | 9 +- package-lock.json | 370 +++++++++++++------------------- package.json | 10 +- spec/ParseGraphQLServer.spec.js | 13 +- 6 files changed, 179 insertions(+), 254 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 628903944d..96ed13b0c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: branches: - '**' env: - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 PARSE_SERVER_TEST_TIMEOUT: 20000 jobs: check-ci: @@ -105,43 +105,43 @@ jobs: MONGODB_VERSION: 5.0.3 MONGODB_TOPOLOGY: replicaset MONGODB_STORAGE_ENGINE: wiredTiger - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: MongoDB 4.4, ReplicaSet, WiredTiger MONGODB_VERSION: 4.4.10 MONGODB_TOPOLOGY: replicaset MONGODB_STORAGE_ENGINE: wiredTiger - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: MongoDB 4.2, ReplicaSet, WiredTiger MONGODB_VERSION: 4.2.17 MONGODB_TOPOLOGY: replicaset MONGODB_STORAGE_ENGINE: wiredTiger - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: MongoDB 4.0, ReplicaSet, WiredTiger MONGODB_VERSION: 4.0.27 MONGODB_TOPOLOGY: replicaset MONGODB_STORAGE_ENGINE: wiredTiger - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: MongoDB 4.0, Standalone, MMAPv1 MONGODB_VERSION: 4.0.27 MONGODB_TOPOLOGY: standalone MONGODB_STORAGE_ENGINE: mmapv1 - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: Redis Cache PARSE_SERVER_TEST_CACHE: redis MONGODB_VERSION: 4.4.10 MONGODB_TOPOLOGY: standalone MONGODB_STORAGE_ENGINE: wiredTiger - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: Node 12 MONGODB_VERSION: 4.4.10 MONGODB_TOPOLOGY: standalone MONGODB_STORAGE_ENGINE: wiredTiger NODE_VERSION: 12.22.7 - - name: Node 15 + - name: Node 14 MONGODB_VERSION: 4.4.10 MONGODB_TOPOLOGY: standalone MONGODB_STORAGE_ENGINE: wiredTiger - NODE_VERSION: 15.14.0 + NODE_VERSION: 14.18.1 fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 @@ -183,19 +183,19 @@ jobs: include: - name: PostgreSQL 11, PostGIS 3.0 POSTGRES_IMAGE: postgis/postgis:11-3.0 - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: PostgreSQL 11, PostGIS 3.1 POSTGRES_IMAGE: postgis/postgis:11-3.1 - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: PostgreSQL 12, PostGIS 3.1 POSTGRES_IMAGE: postgis/postgis:12-3.1 - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: PostgreSQL 13, PostGIS 3.1 POSTGRES_IMAGE: postgis/postgis:13-3.1 - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 - name: PostgreSQL 14, PostGIS 3.1 POSTGRES_IMAGE: postgis/postgis:14-3.1 - NODE_VERSION: 14.18.1 + NODE_VERSION: 16.13.0 fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 diff --git a/README.md b/README.md index 5a8a5d7dcf..73870981c9 100644 --- a/README.md +++ b/README.md @@ -116,8 +116,7 @@ Parse Server is continuously tested with the most recent releases of Node.js to |------------|----------------|-------------|---------------| | Node.js 12 | 12.22.7 | April 2022 | ✅ Yes | | Node.js 14 | 14.18.1 | April 2023 | ✅ Yes | -| Node.js 15 | 15.14.0 | June 2021 | ✅ Yes | -| Node.js 16 | 16.x.x | April 2024 | ❌ Not tested | +| Node.js 16 | 16.13.0 | April 2024 | ✅ Yes | #### MongoDB Parse Server is continuously tested with the most recent releases of MongoDB to ensure compatibility. We follow the [MongoDB support schedule](https://www.mongodb.com/support-policy) and only test against versions that are officially supported and have not reached their end-of-life date. diff --git a/ci/ciCheck.js b/ci/ciCheck.js index e1d968be19..2ad5c3e8f3 100644 --- a/ci/ciCheck.js +++ b/ci/ciCheck.js @@ -1,4 +1,4 @@ -'use strict' +'use strict'; const CiVersionCheck = require('./CiVersionCheck'); const mongoVersionList = require('mongodb-version-list'); @@ -14,9 +14,8 @@ async function check() { * Check the MongoDB versions used in test environments. */ async function checkMongoDbVersions() { - const releasedVersions = await new Promise((resolve, reject) => { - mongoVersionList(function(error, versions) { + mongoVersionList(function (error, versions) { if (error) { reject(error); } @@ -47,7 +46,6 @@ async function checkMongoDbVersions() { * Check the Nodejs versions used in test environments. */ async function checkNodeVersions() { - const allVersions = await allNodeVersions(); const releasedVersions = allVersions.versions; @@ -62,7 +60,8 @@ async function checkNodeVersions() { ignoreReleasedVersions: [ '<12.0.0', // These versions have reached their end-of-life support date '>=13.0.0 <14.0.0', // These versions have reached their end-of-life support date - '>=16.0.0', // This version has not been officially released yet + '>=15.0.0 <16.0.0', // These versions have reached their end-of-life support date + '>=17.0.0', // These versions are not officially supported yet ], }).check(); } diff --git a/package-lock.json b/package-lock.json index 9e541d2732..b9c7f8ac69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,10 @@ "dev": true }, "@apollo/client": { - "version": "3.4.8", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.4.8.tgz", - "integrity": "sha512-/cNqTSwc2Dw8q6FDDjdd30+yvhP7rI0Fvl3Hbro0lTtFuhzkevfNyQaI2jAiOrjU6Jc0RbanxULaNrX7UmvjSQ==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.4.17.tgz", + "integrity": "sha512-MDt2rwMX1GqodiVEKJqmDmAz8xr0qJmq5PdWeIt0yDaT4GOkKYWZiWkyfhfv3raTk8PyJvbsNG9q2CqmUrlGfg==", + "dev": true, "requires": { "@graphql-typed-document-node/core": "^3.0.0", "@wry/context": "^0.6.0", @@ -26,21 +27,23 @@ "symbol-observable": "^4.0.0", "ts-invariant": "^0.9.0", "tslib": "^2.3.0", - "zen-observable-ts": "^1.1.0" + "zen-observable-ts": "~1.1.0" }, "dependencies": { "@wry/equality": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.2.tgz", "integrity": "sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA==", + "dev": true, "requires": { "tslib": "^2.3.0" } }, "ts-invariant": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.1.tgz", - "integrity": "sha512-hSeYibh29ULlHkuEfukcoiyTct+s2RzczMLTv4x3NWC/YrBy7x7ps5eYq/b4Y3Sb9/uAlf54+/5CAEMVxPhuQw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.3.tgz", + "integrity": "sha512-HinBlTbFslQI0OHP07JLsSXPibSegec6r9ai5xxq/qHYCsIQbzpymLpDhAUsnXcSrDEcd0L62L8vsOEdzM0qlA==", + "dev": true, "requires": { "tslib": "^2.1.0" } @@ -48,12 +51,14 @@ "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true }, "zen-observable-ts": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", + "dev": true, "requires": { "@types/zen-observable": "0.8.3", "zen-observable": "0.8.15" @@ -1104,6 +1109,7 @@ "version": "7.15.3", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz", "integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==", + "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } @@ -1192,6 +1198,37 @@ "tslib": "~2.0.1" } }, + "@graphql-tools/batch-execute": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.3.1.tgz", + "integrity": "sha512-63kHY8ZdoO5FoeDXYHnAak1R3ysMViMPwWC2XUblFckuVLMUPmB2ONje8rjr2CvzWBHAW8c1Zsex+U3xhKtGIA==", + "requires": { + "@graphql-tools/utils": "^8.5.1", + "dataloader": "2.0.0", + "tslib": "~2.3.0", + "value-or-promise": "1.0.11" + }, + "dependencies": { + "@graphql-tools/utils": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.5.3.tgz", + "integrity": "sha512-HDNGWFVa8QQkoQB0H1lftvaO1X5xUaUDk1zr1qDe0xN1NL0E/CrQdJ5UKLqOvH4hkqVUPxQsyOoAZFkaH6rLHg==", + "requires": { + "tslib": "~2.3.0" + } + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "value-or-promise": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz", + "integrity": "sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==" + } + } + }, "@graphql-tools/delegate": { "version": "6.2.4", "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-6.2.4.tgz", @@ -1206,45 +1243,86 @@ } }, "@graphql-tools/links": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/links/-/links-6.2.5.tgz", - "integrity": "sha512-XeGDioW7F+HK6HHD/zCeF0HRC9s12NfOXAKv1HC0J7D50F4qqMvhdS/OkjzLoBqsgh/Gm8icRc36B5s0rOA9ig==", - "requires": { - "@graphql-tools/utils": "^7.0.0", - "apollo-link": "1.2.14", - "apollo-upload-client": "14.1.2", - "cross-fetch": "3.0.6", - "form-data": "3.0.0", - "is-promise": "4.0.0", - "tslib": "~2.0.1" + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/links/-/links-8.2.1.tgz", + "integrity": "sha512-J0igz42eKh/RQxDZPdEE4YiztY3zWTBcsn/bUtJp52XKNj0EIO0fR6WLEocT6uxgWCNnWYPOQUaf7bEgeW44Vg==", + "requires": { + "@graphql-tools/delegate": "^8.4.1", + "@graphql-tools/utils": "^8.5.1", + "apollo-upload-client": "16.0.0", + "cross-fetch": "3.1.4", + "form-data": "4.0.0", + "tslib": "~2.3.0" }, "dependencies": { + "@graphql-tools/delegate": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.4.2.tgz", + "integrity": "sha512-CjggOhiL4WtyG2I3kux+1/p8lQxSFHBj0gwa0NxnQ6Vsnpw7Ig5VP1ovPnitFuBv2k4QdC37Nj2xv2n7DRn8fw==", + "requires": { + "@graphql-tools/batch-execute": "^8.3.1", + "@graphql-tools/schema": "^8.3.1", + "@graphql-tools/utils": "^8.5.3", + "dataloader": "2.0.0", + "tslib": "~2.3.0", + "value-or-promise": "1.0.11" + } + }, + "@graphql-tools/merge": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.1.tgz", + "integrity": "sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA==", + "requires": { + "@graphql-tools/utils": "^8.5.1", + "tslib": "~2.3.0" + } + }, + "@graphql-tools/schema": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.1.tgz", + "integrity": "sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ==", + "requires": { + "@graphql-tools/merge": "^8.2.1", + "@graphql-tools/utils": "^8.5.1", + "tslib": "~2.3.0", + "value-or-promise": "1.0.11" + } + }, "@graphql-tools/utils": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-7.10.0.tgz", - "integrity": "sha512-d334r6bo9mxdSqZW6zWboEnnOOFRrAPVQJ7LkU8/6grglrbcu6WhwCLzHb90E94JI3TD3ricC3YGbUqIi9Xg0w==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.5.3.tgz", + "integrity": "sha512-HDNGWFVa8QQkoQB0H1lftvaO1X5xUaUDk1zr1qDe0xN1NL0E/CrQdJ5UKLqOvH4hkqVUPxQsyOoAZFkaH6rLHg==", "requires": { - "@ardatan/aggregate-error": "0.0.6", - "camel-case": "4.1.2", - "tslib": "~2.2.0" - }, - "dependencies": { - "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==" - } + "tslib": "~2.3.0" } }, "apollo-upload-client": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-14.1.2.tgz", - "integrity": "sha512-ozaW+4tnVz1rpfwiQwG3RCdCcZ93RV/37ZQbRnObcQ9mjb+zur58sGDPVg9Ef3fiujLmiE/Fe9kdgvIMA3VOjA==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-16.0.0.tgz", + "integrity": "sha512-aLhYucyA0T8aBEQ5g+p13qnR9RUyL8xqb8FSZ7e/Kw2KUOsotLUlFluLobqaE7JSUFwc6sKfXIcwB7y4yEjbZg==", "requires": { - "@apollo/client": "^3.1.5", - "@babel/runtime": "^7.11.2", - "extract-files": "^9.0.0" + "extract-files": "^11.0.0" } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "value-or-promise": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz", + "integrity": "sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==" } } }, @@ -1387,9 +1465,10 @@ } }, "@graphql-typed-document-node/core": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz", - "integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", + "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", + "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -2582,7 +2661,8 @@ "@types/zen-observable": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" + "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==", + "dev": true }, "@typescript-eslint/types": { "version": "4.31.0", @@ -2662,6 +2742,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz", "integrity": "sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw==", + "dev": true, "requires": { "tslib": "^2.3.0" }, @@ -2669,7 +2750,8 @@ "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true } } }, @@ -2692,6 +2774,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.1.tgz", "integrity": "sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw==", + "dev": true, "requires": { "tslib": "^2.3.0" }, @@ -2699,7 +2782,8 @@ "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true } } }, @@ -2910,24 +2994,6 @@ } } }, - "apollo-cache": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.5.tgz", - "integrity": "sha512-1XoDy8kJnyWY/i/+gLTEbYLnoiVtS8y7ikBr/IfmML4Qb+CM7dEEbIUOjnY716WqmZ/UpXIxTfJsY7rMcqiCXA==", - "dev": true, - "requires": { - "apollo-utilities": "^1.3.4", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "apollo-cache-control": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.14.0.tgz", @@ -2937,76 +3003,6 @@ "apollo-server-plugin-base": "^0.13.0" } }, - "apollo-cache-inmemory": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.6.tgz", - "integrity": "sha512-L8pToTW/+Xru2FFAhkZ1OA9q4V4nuvfoPecBM34DecAugUZEBhI2Hmpgnzq2hTKZ60LAMrlqiASm0aqAY6F8/A==", - "dev": true, - "requires": { - "apollo-cache": "^1.3.5", - "apollo-utilities": "^1.3.4", - "optimism": "^0.10.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "@wry/context": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.4.4.tgz", - "integrity": "sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag==", - "dev": true, - "requires": { - "@types/node": ">=6", - "tslib": "^1.9.3" - } - }, - "optimism": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.10.3.tgz", - "integrity": "sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw==", - "dev": true, - "requires": { - "@wry/context": "^0.4.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "apollo-client": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.6.10.tgz", - "integrity": "sha512-jiPlMTN6/5CjZpJOkGeUV0mb4zxx33uXWdj/xQCfAMkuNAC3HN7CvYDyMHHEzmcQ5GV12LszWoQ/VlxET24CtA==", - "dev": true, - "requires": { - "@types/zen-observable": "^0.8.0", - "apollo-cache": "1.3.5", - "apollo-link": "^1.0.0", - "apollo-utilities": "1.3.4", - "symbol-observable": "^1.0.2", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0", - "zen-observable": "^0.8.0" - }, - "dependencies": { - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "apollo-datasource": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.9.0.tgz", @@ -3044,62 +3040,6 @@ } } }, - "apollo-link-http": { - "version": "1.5.17", - "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.17.tgz", - "integrity": "sha512-uWcqAotbwDEU/9+Dm9e1/clO7hTB2kQ/94JYcGouBVLjoKmTeJTUPQKcJGpPwUjZcSqgYicbFqQSoJIW0yrFvg==", - "dev": true, - "requires": { - "apollo-link": "^1.2.14", - "apollo-link-http-common": "^0.2.16", - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "apollo-link-http-common": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz", - "integrity": "sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg==", - "dev": true, - "requires": { - "apollo-link": "^1.2.14", - "ts-invariant": "^0.4.0", - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "apollo-link-ws": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/apollo-link-ws/-/apollo-link-ws-1.0.20.tgz", - "integrity": "sha512-mjSFPlQxmoLArpHBeUb2Xj+2HDYeTaJqFGOqQ+I8NVJxgL9lJe84PDWcPah/yMLv3rB7QgBDSuZ0xoRFBPlySw==", - "dev": true, - "requires": { - "apollo-link": "^1.2.14", - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "apollo-reporting-protobuf": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", @@ -3300,23 +3240,12 @@ } }, "apollo-upload-client": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-13.0.0.tgz", - "integrity": "sha512-lJ9/bk1BH1lD15WhWRha2J3+LrXrPIX5LP5EwiOUHv8PCORp4EUrcujrA3rI5hZeZygrTX8bshcuMdpqpSrvtA==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-16.0.0.tgz", + "integrity": "sha512-aLhYucyA0T8aBEQ5g+p13qnR9RUyL8xqb8FSZ7e/Kw2KUOsotLUlFluLobqaE7JSUFwc6sKfXIcwB7y4yEjbZg==", "dev": true, "requires": { - "@babel/runtime": "^7.9.2", - "apollo-link": "^1.2.12", - "apollo-link-http-common": "^0.2.14", - "extract-files": "^8.0.0" - }, - "dependencies": { - "extract-files": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-8.1.0.tgz", - "integrity": "sha512-PTGtfthZK79WUMk+avLmwx3NGdU8+iVFXC2NMGxKsn0MnihOG2lvumj+AZo8CTwTrwjXDgZ5tztbRlEdRjBonQ==", - "dev": true - } + "extract-files": "^11.0.0" } }, "apollo-utilities": { @@ -4004,15 +3933,6 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -4892,9 +4812,9 @@ } }, "cross-fetch": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", - "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", + "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", "requires": { "node-fetch": "2.6.1" } @@ -6642,9 +6562,9 @@ } }, "extract-files": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz", - "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==" + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz", + "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==" }, "extsprintf": { "version": "1.4.0", @@ -7108,6 +7028,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -7729,6 +7650,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, "requires": { "react-is": "^16.7.0" } @@ -8892,7 +8814,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "3.14.1", @@ -9826,6 +9749,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -13229,6 +13153,7 @@ "version": "0.16.1", "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz", "integrity": "sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg==", + "dev": true, "requires": { "@wry/context": "^0.6.0", "@wry/trie": "^0.3.0" @@ -14034,6 +13959,7 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -14186,7 +14112,8 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "react-native-crypto-js": { "version": "1.0.0", @@ -15861,7 +15788,8 @@ "symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==" + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true }, "table": { "version": "5.4.6", diff --git a/package.json b/package.json index b78ebfb986..e6d1da255f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "license": "BSD-3-Clause", "dependencies": { "@apollographql/graphql-playground-html": "1.6.29", - "@graphql-tools/links": "6.2.5", + "@graphql-tools/links": "8.2.1", "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", "@parse/fs-files-adapter": "1.2.1", @@ -62,6 +62,7 @@ }, "devDependencies": { "@actions/core": "1.2.6", + "@apollo/client": "3.4.17", "@babel/cli": "7.10.0", "@babel/core": "7.10.0", "@babel/plugin-proposal-object-rest-spread": "7.10.0", @@ -75,12 +76,7 @@ "@semantic-release/npm": "7.1.3", "@semantic-release/release-notes-generator": "9.0.3", "all-node-versions": "8.0.0", - "apollo-cache-inmemory": "1.6.6", - "apollo-client": "2.6.10", - "apollo-link": "1.2.14", - "apollo-link-http": "1.5.17", - "apollo-link-ws": "1.0.20", - "apollo-upload-client": "13.0.0", + "apollo-upload-client": "16.0.0", "apollo-utilities": "1.3.4", "babel-eslint": "10.1.0", "bcrypt-nodejs": "0.0.3", diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 52427efcc2..50f54c55b4 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -9,13 +9,16 @@ const { updateCLP } = require('./support/dev'); const pluralize = require('pluralize'); const { getMainDefinition } = require('apollo-utilities'); -const { ApolloLink, split } = require('apollo-link'); -const { createHttpLink } = require('apollo-link-http'); -const { InMemoryCache } = require('apollo-cache-inmemory'); const { createUploadLink } = require('apollo-upload-client'); const { SubscriptionClient } = require('subscriptions-transport-ws'); -const { WebSocketLink } = require('apollo-link-ws'); -const ApolloClient = require('apollo-client').default; +const { WebSocketLink } = require('@apollo/client/link/ws'); +const { + ApolloClient, + InMemoryCache, + ApolloLink, + split, + createHttpLink, +} = require('@apollo/client/core'); const gql = require('graphql-tag'); const { toGlobalId } = require('graphql-relay'); const { From fea308a01ad9739b2b430ebe2164b967308b6725 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 18 Nov 2021 22:38:42 +0000 Subject: [PATCH 16/83] chore(release): 5.0.0-alpha.8 [skip ci] # [5.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.7...5.0.0-alpha.8) (2021-11-18) ### Features * add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1)) ### BREAKING CHANGES * Removes official Node 15 support which has reached it end-of-life date. ([45cc58c](45cc58c)) --- changelogs/CHANGELOG_alpha.md | 12 ++++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index cd67f72253..e600538a78 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,15 @@ +# [5.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.7...5.0.0-alpha.8) (2021-11-18) + + +### Features + +* add support for Node 16 ([#7707](https://github.com/parse-community/parse-server/issues/7707)) ([45cc58c](https://github.com/parse-community/parse-server/commit/45cc58c7e5e640a46c5d508019a3aa81242964b1)) + + +### BREAKING CHANGES + +* Removes official Node 15 support which has reached it end-of-life date. ([45cc58c](45cc58c)) + # [5.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.6...5.0.0-alpha.7) (2021-11-12) diff --git a/package-lock.json b/package-lock.json index b9c7f8ac69..12f9e74bf5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.7", + "version": "5.0.0-alpha.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e6d1da255f..73bb74b099 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.7", + "version": "5.0.0-alpha.8", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 899da8d765d9a8e2ced42364014d3b3017fd3063 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Thu, 18 Nov 2021 23:44:10 +0100 Subject: [PATCH 17/83] docs: remove node 15 from badge; add node 17 to compatibility table (#7709) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 73870981c9..f2ecce98ab 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Coverage](https://img.shields.io/codecov/c/github/parse-community/parse-server/alpha.svg)](https://codecov.io/github/parse-community/parse-server?branch=alpha) [![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases) -[![Node Version](https://img.shields.io/badge/nodejs-12,_14,_15-green.svg?logo=node.js&style=flat)](https://nodejs.org) +[![Node Version](https://img.shields.io/badge/nodejs-12,_14,_16-green.svg?logo=node.js&style=flat)](https://nodejs.org) [![MongoDB Version](https://img.shields.io/badge/mongodb-4.0,_4.2,_4.4,_5.0-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com) [![Postgres Version](https://img.shields.io/badge/postgresql-11,_12,_13,_14-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org) @@ -117,6 +117,7 @@ Parse Server is continuously tested with the most recent releases of Node.js to | Node.js 12 | 12.22.7 | April 2022 | ✅ Yes | | Node.js 14 | 14.18.1 | April 2023 | ✅ Yes | | Node.js 16 | 16.13.0 | April 2024 | ✅ Yes | +| Node.js 17 | 17.x | June 2022 | ❌ Not tested | #### MongoDB Parse Server is continuously tested with the most recent releases of MongoDB to ensure compatibility. We follow the [MongoDB support schedule](https://www.mongodb.com/support-policy) and only test against versions that are officially supported and have not reached their end-of-life date. From 260290409e747414c703ddec755d5cba73be5e83 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 21 Nov 2021 14:49:37 +0100 Subject: [PATCH 18/83] refactor: upgrade follow-redirects from 1.14.4 to 1.14.5 (#7712) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 12f9e74bf5..3271c17932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6990,9 +6990,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index 73bb74b099..613a1dc2c5 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "cors": "2.8.5", "deepcopy": "2.1.0", "express": "4.17.1", - "follow-redirects": "1.14.4", + "follow-redirects": "1.14.5", "graphql": "15.7.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.9.0", From c789f6c97992f0c68d1c07aae19239932e238701 Mon Sep 17 00:00:00 2001 From: Corey Date: Thu, 25 Nov 2021 10:16:46 -0800 Subject: [PATCH 19/83] refactor: test moved to correct test group (#7717) --- spec/CloudCode.spec.js | 38 +++++++++++++-------------- src/Controllers/DatabaseController.js | 4 +-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index d5e6113763..c185eac53e 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -1999,6 +1999,25 @@ describe('beforeFind hooks', () => { }); }); + it('should have object found with nested relational data query', async () => { + const obj1 = Parse.Object.extend('TestObject'); + const obj2 = Parse.Object.extend('TestObject2'); + let item2 = new obj2(); + item2 = await item2.save(); + let item1 = new obj1(); + const relation = item1.relation('rel'); + relation.add(item2); + item1 = await item1.save(); + Parse.Cloud.beforeFind('TestObject', req => { + const additionalQ = new Parse.Query('TestObject'); + additionalQ.equalTo('rel', item2); + return Parse.Query.and(req.query, additionalQ); + }); + const q = new Parse.Query('TestObject'); + const res = await q.first(); + expect(res.id).toEqual(item1.id); + }); + it('should use the modified exclude query', async () => { Parse.Cloud.beforeFind('MyObject', req => { const q = req.query; @@ -3516,23 +3535,4 @@ describe('sendEmail', () => { 'Failed to send email because no mail adapter is configured for Parse Server.' ); }); - - it('should have object found with nested relational data query', async () => { - const obj1 = Parse.Object.extend('TestObject'); - const obj2 = Parse.Object.extend('TestObject2'); - let item2 = new obj2(); - item2 = await item2.save(); - let item1 = new obj1(); - const relation = item1.relation('rel'); - relation.add(item2); - item1 = await item1.save(); - Parse.Cloud.beforeFind('TestObject', req => { - const additionalQ = new Parse.Query('TestObject'); - additionalQ.equalTo('rel', item2); - return Parse.Query.and(req.query, additionalQ); - }); - const q = new Parse.Query('TestObject'); - const res = await q.first(); - expect(res.id).toEqual(item1.id); - }); }); diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 20d5c4ba66..158308ded3 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -972,9 +972,9 @@ class DatabaseController { }); } if (query['$and']) { - const ors = query['$and']; + const ands = query['$and']; return Promise.all( - ors.map((aQuery, index) => { + ands.map((aQuery, index) => { return this.reduceInRelation(className, aQuery, schema).then(aQuery => { query['$and'][index] = aQuery; }); From ed86c807721cc52a1a5a9dea0b768717eec269ed Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Sat, 27 Nov 2021 12:27:08 +0100 Subject: [PATCH 20/83] fix: unable to use objectId size higher than 19 on GraphQL API (#7627) --- package-lock.json | 6 ++-- package.json | 2 +- spec/ParseGraphQLServer.spec.js | 29 +++++++++++++++---- .../Postgres/PostgresStorageAdapter.js | 8 ++++- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3271c17932..879c91eb75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7417,9 +7417,9 @@ "integrity": "sha512-9TSAwcVA3KWw7JWYep5NCk2aw3wl1ayLtbMpmG7l26vh1FZ+gZexNPP+XJfUFyJa71UU0zcKSgtgpsrsA3Xv9Q==" }, "graphql-relay": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/graphql-relay/-/graphql-relay-0.9.0.tgz", - "integrity": "sha512-yNJLCqcjz0XpzpmmckRJCSK8a2ZLwTurwrQ09UyGftONh52PbrGpK1UO4yspvj0c7pC+jkN4ZUqVXG3LRrWkXQ==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/graphql-relay/-/graphql-relay-0.7.0.tgz", + "integrity": "sha512-P8eS3IbZRhbfbcfud1Q6VPrIru4hchkb15MuOij+WQo9r0chD5NBIxiVjuRE2iG2EMHxIOrZb8LnMe82+YdITA==" }, "graphql-subscriptions": { "version": "1.2.1", diff --git a/package.json b/package.json index 613a1dc2c5..a1479d3d6e 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "follow-redirects": "1.14.5", "graphql": "15.7.0", "graphql-list-fields": "2.0.2", - "graphql-relay": "0.9.0", + "graphql-relay": "0.7.0", "graphql-tag": "2.12.5", "graphql-upload": "11.0.0", "intersect": "1.0.1", diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 50f54c55b4..58b26e4b65 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2287,8 +2287,7 @@ describe('ParseGraphQLServer', () => { expect(nodeResult.data.node2.objectId).toBe(obj2.id); expect(nodeResult.data.node2.someField).toBe('some value 2'); }); - // TODO: (moumouls, davimacedo) Fix flaky test - xit('Id inputs should work either with global id or object id', async () => { + it('Id inputs should work either with global id or object id', async () => { try { await apolloClient.mutate({ mutation: gql` @@ -2595,9 +2594,12 @@ describe('ParseGraphQLServer', () => { .map(value => value.node.someField) .sort() ).toEqual(['some value 22', 'some value 44']); - expect( - findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.id - ).toBeLessThan(findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.id); + // NOTE: Here @davimacedo tried to test RelayID order, but the test is wrong since + // "objectId1" < "objectId2" do not always keep the order when objectId is transformed + // to base64 by Relay + // "SecondaryObject:bBRgmzIRRM" < "SecondaryObject:nTMcuVbATY" true + // base64("SecondaryObject:bBRgmzIRRM"") < base64(""SecondaryObject:nTMcuVbATY"") false + // "U2Vjb25kYXJ5T2JqZWN0OmJCUmdteklSUk0=" < "U2Vjb25kYXJ5T2JqZWN0Om5UTWN1VmJBVFk=" false expect( findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.objectId ).toBeLessThan( @@ -2763,6 +2765,23 @@ describe('ParseGraphQLServer', () => { handleError(e); } }); + it('Id inputs should work either with global id or object id with objectId higher than 19', async () => { + await reconfigureServer({ objectIdSize: 20 }); + const obj = new Parse.Object('SomeClass'); + await obj.save({ name: 'aname', type: 'robot' }); + const result = await apolloClient.query({ + query: gql` + query getSomeClass($id: ID!) { + someClass(id: $id) { + objectId + id + } + } + `, + variables: { id: obj.id }, + }); + expect(result.data.someClass.objectId).toEqual(obj.id); + }); }); }); diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index e6c2bdbb1b..f787d9f1a9 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -1807,7 +1807,13 @@ export class PostgresStorageAdapter implements StorageAdapter { if (key === 'ACL') { memo.push('_rperm'); memo.push('_wperm'); - } else if (key.length > 0) { + } else if ( + key.length > 0 && + // Remove selected field not referenced in the schema + // Relation is not a column in postgres + // $score is a Parse special field and is also not a column + ((schema.fields[key] && schema.fields[key].type !== 'Relation') || key === '$score') + ) { memo.push(key); } return memo; From 1b4d9324de6834b98026d3e8af0536af1adf532a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 27 Nov 2021 11:28:15 +0000 Subject: [PATCH 21/83] chore(release): 5.0.0-alpha.9 [skip ci] # [5.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.8...5.0.0-alpha.9) (2021-11-27) ### Bug Fixes * unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index e600538a78..7407c8ea99 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.8...5.0.0-alpha.9) (2021-11-27) + + +### Bug Fixes + +* unable to use objectId size higher than 19 on GraphQL API ([#7627](https://github.com/parse-community/parse-server/issues/7627)) ([ed86c80](https://github.com/parse-community/parse-server/commit/ed86c807721cc52a1a5a9dea0b768717eec269ed)) + # [5.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.7...5.0.0-alpha.8) (2021-11-18) diff --git a/package-lock.json b/package-lock.json index 879c91eb75..b91276061a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.8", + "version": "5.0.0-alpha.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a1479d3d6e..92684992fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.8", + "version": "5.0.0-alpha.9", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 35ac4c3e68bcf6c5d33002cfd5094a1279bb2bca Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 28 Nov 2021 15:44:33 +0100 Subject: [PATCH 22/83] refactor: upgrade subscriptions-transport-ws from 0.10.0 to 0.11.0 (#7727) --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index b91276061a..5e422bd5ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15726,9 +15726,9 @@ } }, "subscriptions-transport-ws": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.10.0.tgz", - "integrity": "sha512-k28LhLn3abJ1mowFW+LP4QGggE0e3hrk55zXbMHyAeZkCUYtC0owepiwqMD3zX8DglQVaxnhE760pESrNSEzpg==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz", + "integrity": "sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==", "requires": { "backo2": "^1.0.2", "eventemitter3": "^3.1.0", @@ -15743,9 +15743,9 @@ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==" } } }, diff --git a/package.json b/package.json index 92684992fd..b927d7cff1 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pluralize": "8.0.0", "redis": "3.1.2", "semver": "7.3.5", - "subscriptions-transport-ws": "0.10.0", + "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", "uuid": "8.3.2", "winston": "3.3.3", From 7dad413a175631db32d6f8ef6b36e63a79f0609b Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Mon, 29 Nov 2021 17:58:02 +0100 Subject: [PATCH 23/83] refactor: upgrade graphql-tag from 2.12.5 to 2.12.6 (#7726) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e422bd5ac..0e9f6f7a38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7430,9 +7430,9 @@ } }, "graphql-tag": { - "version": "2.12.5", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.5.tgz", - "integrity": "sha512-5xNhP4063d16Pz3HBtKprutsPrmHZi5IdUGOWRxA2B6VF7BIRGOHZ5WQvDmJXZuPcBg7rYwaFxvQYjqkSdR3TQ==", + "version": "2.12.6", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", + "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", "requires": { "tslib": "^2.1.0" }, diff --git a/package.json b/package.json index b927d7cff1..8fd71e9c23 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "graphql": "15.7.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.7.0", - "graphql-tag": "2.12.5", + "graphql-tag": "2.12.6", "graphql-upload": "11.0.0", "intersect": "1.0.1", "jsonwebtoken": "8.5.1", From d4c1f473073764cb0570c633fc4a30669c2ce889 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Mon, 29 Nov 2021 18:19:48 +0100 Subject: [PATCH 24/83] fix: upgrade parse from 3.3.1 to 3.4.0 (#7723) --- package-lock.json | 33 +++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e9f6f7a38..2082094e0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13436,25 +13436,34 @@ } }, "parse": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/parse/-/parse-3.3.1.tgz", - "integrity": "sha512-jrb8tpeanh49lIXuQYbaJoMzywX9YiBtM17aCvYGfaHYJipSTHABA774t8IZap+F8Pb4GgZ0fM4ObfiuO4395A==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.0.tgz", + "integrity": "sha512-FMZLxPW6PvrBgxkXc9AmnYsFKvPwiS4G2n9OI4mdfiSoNzIVLc+bXzlUdJ+I7hiqHsBTP0BrdQczw2/cnVkJ6w==", "requires": { - "@babel/runtime": "7.14.8", - "@babel/runtime-corejs3": "7.14.6", + "@babel/runtime": "7.15.4", + "@babel/runtime-corejs3": "7.14.7", "crypto-js": "4.1.1", "idb-keyval": "5.0.6", "react-native-crypto-js": "1.0.0", "uuid": "3.4.0", - "ws": "7.5.0", + "ws": "7.5.1", "xmlhttprequest": "1.8.0" }, "dependencies": { "@babel/runtime": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", - "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz", + "integrity": "sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==", "requires": { + "core-js-pure": "^3.15.0", "regenerator-runtime": "^0.13.4" } }, @@ -13464,9 +13473,9 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "ws": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", - "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==" + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", + "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==" } } }, diff --git a/package.json b/package.json index 8fd71e9c23..ea4a29ca26 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "mime": "2.5.2", "mongodb": "3.6.11", "mustache": "4.2.0", - "parse": "3.3.1", + "parse": "3.4.0", "pg-monitor": "1.4.1", "pg-promise": "10.11.1", "pluralize": "8.0.0", From 37ac29d79868916085a97d75f8f33231423808b9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 29 Nov 2021 17:20:43 +0000 Subject: [PATCH 25/83] chore(release): 5.0.0-alpha.10 [skip ci] # [5.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.9...5.0.0-alpha.10) (2021-11-29) ### Bug Fixes * upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 7407c8ea99..0c5056fc26 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.9...5.0.0-alpha.10) (2021-11-29) + + +### Bug Fixes + +* upgrade parse from 3.3.1 to 3.4.0 ([#7723](https://github.com/parse-community/parse-server/issues/7723)) ([d4c1f47](https://github.com/parse-community/parse-server/commit/d4c1f473073764cb0570c633fc4a30669c2ce889)) + # [5.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.8...5.0.0-alpha.9) (2021-11-27) diff --git a/package-lock.json b/package-lock.json index 2082094e0f..701d99828c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.9", + "version": "5.0.0-alpha.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ea4a29ca26..3f0aa3f92b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.9", + "version": "5.0.0-alpha.10", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From f5ef98bde32083403c0e30a12162fcc1e52cac37 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Tue, 30 Nov 2021 00:50:25 +0100 Subject: [PATCH 26/83] fix: upgrade mime from 2.5.2 to 3.0.0 (#7725) --- package-lock.json | 12 +++++++++--- package.json | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 701d99828c..17f53b4fd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2232,6 +2232,12 @@ "universalify": "^2.0.0" } }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -10177,9 +10183,9 @@ } }, "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" }, "mime-db": { "version": "1.49.0", diff --git a/package.json b/package.json index 3f0aa3f92b..3cca009e8f 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "ldapjs": "2.3.1", "lodash": "4.17.21", "lru-cache": "5.1.1", - "mime": "2.5.2", + "mime": "3.0.0", "mongodb": "3.6.11", "mustache": "4.2.0", "parse": "3.4.0", From e7c7f44265d4d8a9c62a9e3d6910d31dbb243cf8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 29 Nov 2021 23:51:26 +0000 Subject: [PATCH 27/83] chore(release): 5.0.0-alpha.11 [skip ci] # [5.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.10...5.0.0-alpha.11) (2021-11-29) ### Bug Fixes * upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 0c5056fc26..3953b69e93 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.10...5.0.0-alpha.11) (2021-11-29) + + +### Bug Fixes + +* upgrade mime from 2.5.2 to 3.0.0 ([#7725](https://github.com/parse-community/parse-server/issues/7725)) ([f5ef98b](https://github.com/parse-community/parse-server/commit/f5ef98bde32083403c0e30a12162fcc1e52cac37)) + # [5.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.9...5.0.0-alpha.10) (2021-11-29) diff --git a/package-lock.json b/package-lock.json index 17f53b4fd0..ba9b4b9553 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.10", + "version": "5.0.0-alpha.11", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3cca009e8f..2b4823df7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.10", + "version": "5.0.0-alpha.11", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 6a6248b6cb2e732d17131e18e659943b894ed2f1 Mon Sep 17 00:00:00 2001 From: Ben Devore Date: Mon, 6 Dec 2021 18:52:59 -0500 Subject: [PATCH 28/83] fix: adding or modifying a nested property requires addField permissions (#7679) --- spec/schemas.spec.js | 28 +++++++++++++++++++++++++++ src/Controllers/DatabaseController.js | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index 5180b36ca5..e8dcc41e4d 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -1779,6 +1779,34 @@ describe('schemas', () => { }); }); + describe('Nested documents', () => { + beforeAll(async () => { + const testSchema = new Parse.Schema('test_7371'); + testSchema.setCLP({ + create: { ['*']: true }, + update: { ['*']: true }, + addField: {}, + }); + testSchema.addObject('a'); + await testSchema.save(); + }); + + it('addField permission not required for adding a nested property', async () => { + const obj = new Parse.Object('test_7371'); + obj.set('a', {}); + await obj.save(); + obj.set('a.b', 2); + await obj.save(); + }); + it('addField permission not required for modifying a nested property', async () => { + const obj = new Parse.Object('test_7371'); + obj.set('a', { b: 1 }); + await obj.save(); + obj.set('a.b', 2); + await obj.save(); + }); + }); + it('should aceept class-level permission with userid of any length', async done => { await global.reconfigureServer({ customIdSize: 11, diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 158308ded3..42273b6990 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -894,7 +894,7 @@ class DatabaseController { if (object[field] && object[field].__op && object[field].__op === 'Delete') { return false; } - return schemaFields.indexOf(field) < 0; + return schemaFields.indexOf(getRootFieldName(field)) < 0; }); if (newKeys.length > 0) { // adds a marker that new field is being adding during update From ac789c8537dcb775345d2953fd732d4ad864eb61 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Dec 2021 23:54:00 +0000 Subject: [PATCH 29/83] chore(release): 5.0.0-alpha.12 [skip ci] # [5.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.11...5.0.0-alpha.12) (2021-12-06) ### Bug Fixes * adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 3953b69e93..dc0a25ea70 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.11...5.0.0-alpha.12) (2021-12-06) + + +### Bug Fixes + +* adding or modifying a nested property requires addField permissions ([#7679](https://github.com/parse-community/parse-server/issues/7679)) ([6a6248b](https://github.com/parse-community/parse-server/commit/6a6248b6cb2e732d17131e18e659943b894ed2f1)) + # [5.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.10...5.0.0-alpha.11) (2021-11-29) diff --git a/package-lock.json b/package-lock.json index ba9b4b9553..8a367ec9e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.11", + "version": "5.0.0-alpha.12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2b4823df7e..800b235345 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.11", + "version": "5.0.0-alpha.12", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From ea7c01400f992a1263543706fe49b6174758a2d6 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Wed, 8 Dec 2021 11:19:38 +0100 Subject: [PATCH 30/83] fix: node engine compatibility did not include node 16 (#7739) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 800b235345..bd36f2c0c8 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "madge:circular": "node_modules/.bin/madge ./src --circular" }, "engines": { - "node": ">=12.20.0 <16" + "node": ">=12.20.0 <17" }, "bin": { "parse-server": "bin/parse-server" From 191d80b6677f8ee6f6a0ccd3bde2bf6bb50f9a20 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Dec 2021 10:20:38 +0000 Subject: [PATCH 31/83] chore(release): 5.0.0-alpha.13 [skip ci] # [5.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.12...5.0.0-alpha.13) (2021-12-08) ### Bug Fixes * node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index dc0a25ea70..e635c16fba 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.12...5.0.0-alpha.13) (2021-12-08) + + +### Bug Fixes + +* node engine compatibility did not include node 16 ([#7739](https://github.com/parse-community/parse-server/issues/7739)) ([ea7c014](https://github.com/parse-community/parse-server/commit/ea7c01400f992a1263543706fe49b6174758a2d6)) + # [5.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.11...5.0.0-alpha.12) (2021-12-06) diff --git a/package-lock.json b/package-lock.json index 8a367ec9e3..36af9e81f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.12", + "version": "5.0.0-alpha.13", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bd36f2c0c8..c4a519e3a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.12", + "version": "5.0.0-alpha.13", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 9e477591fd2b468286f034caf559261caf953943 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Thu, 30 Dec 2021 23:38:26 +0000 Subject: [PATCH 32/83] refactor: upgrade follow-redirects from 1.14.5 to 1.14.6 (#7755) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 36af9e81f9..37f696f60b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6996,9 +6996,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", + "integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index c4a519e3a5..51a3d5023c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "cors": "2.8.5", "deepcopy": "2.1.0", "express": "4.17.1", - "follow-redirects": "1.14.5", + "follow-redirects": "1.14.6", "graphql": "15.7.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.7.0", From 7448521cb9a30e12215ca3cf61f1243a67c4d51c Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sat, 1 Jan 2022 20:22:03 +0000 Subject: [PATCH 33/83] refactor: upgrade body-parser from 1.19.0 to 1.19.1 (#7756) --- package-lock.json | 138 ++++++++++++++++++++++++++++++---------------- package.json | 2 +- 2 files changed, 90 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index 37f696f60b..38bf6a39a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3645,20 +3645,20 @@ "dev": true }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.1", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" }, "dependencies": { "debug": { @@ -3670,31 +3670,26 @@ } }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" } } }, @@ -3833,9 +3828,9 @@ } }, "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" }, "cache-base": { "version": "1.0.1", @@ -6398,6 +6393,28 @@ "vary": "~1.1.2" }, "dependencies": { + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6406,11 +6423,39 @@ "ms": "2.0.0" } }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -14070,37 +14115,32 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.1", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" } } }, diff --git a/package.json b/package.json index 51a3d5023c..4162381239 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@parse/push-adapter": "3.4.1", "apollo-server-express": "2.25.2", "bcryptjs": "2.4.3", - "body-parser": "1.19.0", + "body-parser": "1.19.1", "commander": "5.1.0", "cors": "2.8.5", "deepcopy": "2.1.0", From 16b1b2a19714535ca805f2dbb3b561d8f6a519a7 Mon Sep 17 00:00:00 2001 From: Corey Date: Sat, 1 Jan 2022 19:10:54 -0500 Subject: [PATCH 34/83] feat: support relativeTime query constraint on Postgres (#7747) --- spec/MongoTransform.spec.js | 23 +-- spec/ParseQuery.spec.js | 125 +++++++---------- spec/PostgresStorageAdapter.spec.js | 129 +++++++++++++++++ src/Adapters/Storage/Mongo/MongoTransform.js | 131 +---------------- .../Postgres/PostgresStorageAdapter.js | 43 +++++- src/Utils.js | 132 ++++++++++++++++++ 6 files changed, 366 insertions(+), 217 deletions(-) diff --git a/spec/MongoTransform.spec.js b/spec/MongoTransform.spec.js index 6834a6b28d..60adb4b7f0 100644 --- a/spec/MongoTransform.spec.js +++ b/spec/MongoTransform.spec.js @@ -4,6 +4,7 @@ const transform = require('../lib/Adapters/Storage/Mongo/MongoTransform'); const dd = require('deep-diff'); const mongodb = require('mongodb'); +const Utils = require('../lib/Utils'); describe('parseObjectToMongoObjectForCreate', () => { it('a basic number', done => { @@ -592,7 +593,7 @@ describe('relativeTimeToDate', () => { describe('In the future', () => { it('should parse valid natural time', () => { const text = 'in 1 year 2 weeks 12 days 10 hours 24 minutes 30 seconds'; - const { result, status, info } = transform.relativeTimeToDate(text, now); + const { result, status, info } = Utils.relativeTimeToDate(text, now); expect(result.toISOString()).toBe('2018-10-22T23:52:46.617Z'); expect(status).toBe('success'); expect(info).toBe('future'); @@ -602,7 +603,7 @@ describe('relativeTimeToDate', () => { describe('In the past', () => { it('should parse valid natural time', () => { const text = '2 days 12 hours 1 minute 12 seconds ago'; - const { result, status, info } = transform.relativeTimeToDate(text, now); + const { result, status, info } = Utils.relativeTimeToDate(text, now); expect(result.toISOString()).toBe('2017-09-24T01:27:04.617Z'); expect(status).toBe('success'); expect(info).toBe('past'); @@ -612,7 +613,7 @@ describe('relativeTimeToDate', () => { describe('From now', () => { it('should equal current time', () => { const text = 'now'; - const { result, status, info } = transform.relativeTimeToDate(text, now); + const { result, status, info } = Utils.relativeTimeToDate(text, now); expect(result.toISOString()).toBe('2017-09-26T13:28:16.617Z'); expect(status).toBe('success'); expect(info).toBe('present'); @@ -621,54 +622,54 @@ describe('relativeTimeToDate', () => { describe('Error cases', () => { it('should error if string is completely gibberish', () => { - expect(transform.relativeTimeToDate('gibberishasdnklasdnjklasndkl123j123')).toEqual({ + expect(Utils.relativeTimeToDate('gibberishasdnklasdnjklasndkl123j123')).toEqual({ status: 'error', info: "Time should either start with 'in' or end with 'ago'", }); }); it('should error if string contains neither `ago` nor `in`', () => { - expect(transform.relativeTimeToDate('12 hours 1 minute')).toEqual({ + expect(Utils.relativeTimeToDate('12 hours 1 minute')).toEqual({ status: 'error', info: "Time should either start with 'in' or end with 'ago'", }); }); it('should error if there are missing units or numbers', () => { - expect(transform.relativeTimeToDate('in 12 hours 1')).toEqual({ + expect(Utils.relativeTimeToDate('in 12 hours 1')).toEqual({ status: 'error', info: 'Invalid time string. Dangling unit or number.', }); - expect(transform.relativeTimeToDate('12 hours minute ago')).toEqual({ + expect(Utils.relativeTimeToDate('12 hours minute ago')).toEqual({ status: 'error', info: 'Invalid time string. Dangling unit or number.', }); }); it('should error on floating point numbers', () => { - expect(transform.relativeTimeToDate('in 12.3 hours')).toEqual({ + expect(Utils.relativeTimeToDate('in 12.3 hours')).toEqual({ status: 'error', info: "'12.3' is not an integer.", }); }); it('should error if numbers are invalid', () => { - expect(transform.relativeTimeToDate('12 hours 123a minute ago')).toEqual({ + expect(Utils.relativeTimeToDate('12 hours 123a minute ago')).toEqual({ status: 'error', info: "'123a' is not an integer.", }); }); it('should error on invalid interval units', () => { - expect(transform.relativeTimeToDate('4 score 7 years ago')).toEqual({ + expect(Utils.relativeTimeToDate('4 score 7 years ago')).toEqual({ status: 'error', info: "Invalid interval: 'score'", }); }); it("should error when string contains 'ago' and 'in'", () => { - expect(transform.relativeTimeToDate('in 1 day 2 minutes ago')).toEqual({ + expect(Utils.relativeTimeToDate('in 1 day 2 minutes ago')).toEqual({ status: 'error', info: "Time cannot have both 'in' and 'ago'", }); diff --git a/spec/ParseQuery.spec.js b/spec/ParseQuery.spec.js index bf870c92b8..6de0957999 100644 --- a/spec/ParseQuery.spec.js +++ b/spec/ParseQuery.spec.js @@ -4766,7 +4766,7 @@ describe('Parse.Query testing', () => { .catch(done.fail); }); - it_only_db('mongo')('should handle relative times correctly', function (done) { + it('should handle relative times correctly', async () => { const now = Date.now(); const obj1 = new Parse.Object('MyCustomObject', { name: 'obj1', @@ -4777,94 +4777,75 @@ describe('Parse.Query testing', () => { ttl: new Date(now - 2 * 24 * 60 * 60 * 1000), // 2 days ago }); - Parse.Object.saveAll([obj1, obj2]) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.greaterThan('ttl', { $relativeTime: 'in 1 day' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - }) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.greaterThan('ttl', { $relativeTime: '1 day ago' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - }) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.lessThan('ttl', { $relativeTime: '5 days ago' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(0); - }) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.greaterThan('ttl', { $relativeTime: '3 days ago' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(2); - }) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.greaterThan('ttl', { $relativeTime: 'now' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(1); - }) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.greaterThan('ttl', { $relativeTime: 'now' }); - q.lessThan('ttl', { $relativeTime: 'in 1 day' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(0); - }) - .then(() => { - const q = new Parse.Query('MyCustomObject'); - q.greaterThan('ttl', { $relativeTime: '1 year 3 weeks ago' }); - return q.find({ useMasterKey: true }); - }) - .then(results => { - expect(results.length).toBe(2); - }) - .then(done, done.fail); + await Parse.Object.saveAll([obj1, obj2]) + const q1 = new Parse.Query('MyCustomObject'); + q1.greaterThan('ttl', { $relativeTime: 'in 1 day' }); + const results1 = await q1.find({ useMasterKey: true }); + expect(results1.length).toBe(1); + + const q2 = new Parse.Query('MyCustomObject'); + q2.greaterThan('ttl', { $relativeTime: '1 day ago' }); + const results2 = await q2.find({ useMasterKey: true }); + expect(results2.length).toBe(1); + + const q3 = new Parse.Query('MyCustomObject'); + q3.lessThan('ttl', { $relativeTime: '5 days ago' }); + const results3 = await q3.find({ useMasterKey: true }); + expect(results3.length).toBe(0); + + const q4 = new Parse.Query('MyCustomObject'); + q4.greaterThan('ttl', { $relativeTime: '3 days ago' }); + const results4 = await q4.find({ useMasterKey: true }); + expect(results4.length).toBe(2); + + const q5 = new Parse.Query('MyCustomObject'); + q5.greaterThan('ttl', { $relativeTime: 'now' }); + const results5 = await q5.find({ useMasterKey: true }); + expect(results5.length).toBe(1); + + const q6 = new Parse.Query('MyCustomObject'); + q6.greaterThan('ttl', { $relativeTime: 'now' }); + q6.lessThan('ttl', { $relativeTime: 'in 1 day' }); + const results6 = await q6.find({ useMasterKey: true }); + expect(results6.length).toBe(0); + + const q7 = new Parse.Query('MyCustomObject'); + q7.greaterThan('ttl', { $relativeTime: '1 year 3 weeks ago' }); + const results7 = await q7.find({ useMasterKey: true }); + expect(results7.length).toBe(2); }); - it_only_db('mongo')('should error on invalid relative time', function (done) { + it('should error on invalid relative time', async () => { const obj1 = new Parse.Object('MyCustomObject', { name: 'obj1', ttl: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000), // 2 days from now }); - + await obj1.save({ useMasterKey: true }); const q = new Parse.Query('MyCustomObject'); q.greaterThan('ttl', { $relativeTime: '-12 bananas ago' }); - obj1 - .save({ useMasterKey: true }) - .then(() => q.find({ useMasterKey: true })) - .then(done.fail, () => done()); + try { + await q.find({ useMasterKey: true }); + fail("Should have thrown error"); + } catch(error) { + expect(error.code).toBe(Parse.Error.INVALID_JSON); + } }); - it_only_db('mongo')('should error when using $relativeTime on non-Date field', function (done) { + it('should error when using $relativeTime on non-Date field', async () => { const obj1 = new Parse.Object('MyCustomObject', { name: 'obj1', nonDateField: 'abcd', ttl: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000), // 2 days from now }); - + await obj1.save({ useMasterKey: true }); const q = new Parse.Query('MyCustomObject'); q.greaterThan('nonDateField', { $relativeTime: '1 day ago' }); - obj1 - .save({ useMasterKey: true }) - .then(() => q.find({ useMasterKey: true })) - .then(done.fail, () => done()); + try { + await q.find({ useMasterKey: true }); + fail("Should have thrown error"); + } catch(error) { + expect(error.code).toBe(Parse.Error.INVALID_JSON); + } }); it('should match complex structure with dot notation when using matchesKeyInQuery', function (done) { diff --git a/spec/PostgresStorageAdapter.spec.js b/spec/PostgresStorageAdapter.spec.js index b042206db2..dfb6bf4100 100644 --- a/spec/PostgresStorageAdapter.spec.js +++ b/spec/PostgresStorageAdapter.spec.js @@ -149,6 +149,135 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => { await expectAsync(adapter.getClass('UnknownClass')).toBeRejectedWith(undefined); }); + it('$relativeTime should error on $eq', async () => { + const tableName = '_User'; + const schema = { + fields: { + objectId: { type: 'String' }, + username: { type: 'String' }, + email: { type: 'String' }, + emailVerified: { type: 'Boolean' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + authData: { type: 'Object' }, + }, + }; + const client = adapter._client; + await adapter.createTable(tableName, schema); + await client.none('INSERT INTO $1:name ($2:name, $3:name) VALUES ($4, $5)', [ + tableName, + 'objectId', + 'username', + 'Bugs', + 'Bunny', + ]); + const database = Config.get(Parse.applicationId).database; + await database.loadSchema({ clearCache: true }); + try { + await database.find( + tableName, + { + createdAt: { + $eq: { + $relativeTime: '12 days ago' + } + } + }, + { } + ); + fail("Should have thrown error"); + } catch(error) { + expect(error.code).toBe(Parse.Error.INVALID_JSON); + } + await dropTable(client, tableName); + }); + + it('$relativeTime should error on $ne', async () => { + const tableName = '_User'; + const schema = { + fields: { + objectId: { type: 'String' }, + username: { type: 'String' }, + email: { type: 'String' }, + emailVerified: { type: 'Boolean' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + authData: { type: 'Object' }, + }, + }; + const client = adapter._client; + await adapter.createTable(tableName, schema); + await client.none('INSERT INTO $1:name ($2:name, $3:name) VALUES ($4, $5)', [ + tableName, + 'objectId', + 'username', + 'Bugs', + 'Bunny', + ]); + const database = Config.get(Parse.applicationId).database; + await database.loadSchema({ clearCache: true }); + try { + await database.find( + tableName, + { + createdAt: { + $ne: { + $relativeTime: '12 days ago' + } + } + }, + { } + ); + fail("Should have thrown error"); + } catch(error) { + expect(error.code).toBe(Parse.Error.INVALID_JSON); + } + await dropTable(client, tableName); + }); + + it('$relativeTime should error on $exists', async () => { + const tableName = '_User'; + const schema = { + fields: { + objectId: { type: 'String' }, + username: { type: 'String' }, + email: { type: 'String' }, + emailVerified: { type: 'Boolean' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + authData: { type: 'Object' }, + }, + }; + const client = adapter._client; + await adapter.createTable(tableName, schema); + await client.none('INSERT INTO $1:name ($2:name, $3:name) VALUES ($4, $5)', [ + tableName, + 'objectId', + 'username', + 'Bugs', + 'Bunny', + ]); + const database = Config.get(Parse.applicationId).database; + await database.loadSchema({ clearCache: true }); + try { + await database.find( + tableName, + { + createdAt: { + $exists: { + $relativeTime: '12 days ago' + } + } + }, + { } + ); + fail("Should have thrown error"); + } catch(error) { + expect(error.code).toBe(Parse.Error.INVALID_JSON); + } + await dropTable(client, tableName); + }); + it('should use index for caseInsensitive query using Postgres', async () => { const tableName = '_User'; const schema = { diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 5578077778..91ad23fa4a 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -2,6 +2,7 @@ import log from '../../../logger'; import _ from 'lodash'; var mongodb = require('mongodb'); var Parse = require('parse/node').Parse; +const Utils = require('../../../Utils'); const transformKey = (className, fieldName, schema) => { // Check if the schema is known since it's a built-in field. @@ -634,133 +635,6 @@ function transformTopLevelAtom(atom, field) { } } -function relativeTimeToDate(text, now = new Date()) { - text = text.toLowerCase(); - - let parts = text.split(' '); - - // Filter out whitespace - parts = parts.filter(part => part !== ''); - - const future = parts[0] === 'in'; - const past = parts[parts.length - 1] === 'ago'; - - if (!future && !past && text !== 'now') { - return { - status: 'error', - info: "Time should either start with 'in' or end with 'ago'", - }; - } - - if (future && past) { - return { - status: 'error', - info: "Time cannot have both 'in' and 'ago'", - }; - } - - // strip the 'ago' or 'in' - if (future) { - parts = parts.slice(1); - } else { - // past - parts = parts.slice(0, parts.length - 1); - } - - if (parts.length % 2 !== 0 && text !== 'now') { - return { - status: 'error', - info: 'Invalid time string. Dangling unit or number.', - }; - } - - const pairs = []; - while (parts.length) { - pairs.push([parts.shift(), parts.shift()]); - } - - let seconds = 0; - for (const [num, interval] of pairs) { - const val = Number(num); - if (!Number.isInteger(val)) { - return { - status: 'error', - info: `'${num}' is not an integer.`, - }; - } - - switch (interval) { - case 'yr': - case 'yrs': - case 'year': - case 'years': - seconds += val * 31536000; // 365 * 24 * 60 * 60 - break; - - case 'wk': - case 'wks': - case 'week': - case 'weeks': - seconds += val * 604800; // 7 * 24 * 60 * 60 - break; - - case 'd': - case 'day': - case 'days': - seconds += val * 86400; // 24 * 60 * 60 - break; - - case 'hr': - case 'hrs': - case 'hour': - case 'hours': - seconds += val * 3600; // 60 * 60 - break; - - case 'min': - case 'mins': - case 'minute': - case 'minutes': - seconds += val * 60; - break; - - case 'sec': - case 'secs': - case 'second': - case 'seconds': - seconds += val; - break; - - default: - return { - status: 'error', - info: `Invalid interval: '${interval}'`, - }; - } - } - - const milliseconds = seconds * 1000; - if (future) { - return { - status: 'success', - info: 'future', - result: new Date(now.valueOf() + milliseconds), - }; - } else if (past) { - return { - status: 'success', - info: 'past', - result: new Date(now.valueOf() - milliseconds), - }; - } else { - return { - status: 'success', - info: 'present', - result: new Date(now.valueOf()), - }; - } -} - // Transforms a query constraint from REST API format to Mongo format. // A constraint is something with fields like $lt. // If it is not a valid constraint but it could be a valid something @@ -813,7 +687,7 @@ function transformConstraint(constraint, field, count = false) { ); } - const parserResult = relativeTimeToDate(val.$relativeTime); + const parserResult = Utils.relativeTimeToDate(val.$relativeTime); if (parserResult.status === 'success') { answer[key] = parserResult.result; break; @@ -1556,7 +1430,6 @@ module.exports = { transformUpdate, transformWhere, mongoObjectToParseObject, - relativeTimeToDate, transformConstraint, transformPointerString, }; diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index f787d9f1a9..de5712b79d 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -7,6 +7,9 @@ import _ from 'lodash'; // @flow-disable-next import { v4 as uuidv4 } from 'uuid'; import sql from './sql'; +import { StorageAdapter } from '../StorageAdapter'; +import type { SchemaType, QueryType, QueryOptions } from '../StorageAdapter'; +const Utils = require('../../../Utils'); const PostgresRelationDoesNotExistError = '42P01'; const PostgresDuplicateRelationError = '42P07'; @@ -22,9 +25,6 @@ const debug = function (...args: any) { log.debug.apply(log, args); }; -import { StorageAdapter } from '../StorageAdapter'; -import type { SchemaType, QueryType, QueryOptions } from '../StorageAdapter'; - const parseTypeToPostgresType = type => { switch (type.type) { case 'String': @@ -374,6 +374,11 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus patterns.push( `(${constraintFieldName} <> $${index} OR ${constraintFieldName} IS NULL)` ); + } else if (typeof fieldValue.$ne === 'object' && fieldValue.$ne.$relativeTime) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + '$relativeTime can only be used with the $lt, $lte, $gt, and $gte operators' + ); } else { patterns.push(`($${index}:name <> $${index + 1} OR $${index}:name IS NULL)`); } @@ -399,6 +404,11 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus if (fieldName.indexOf('.') >= 0) { values.push(fieldValue.$eq); patterns.push(`${transformDotField(fieldName)} = $${index++}`); + } else if (typeof fieldValue.$eq === 'object' && fieldValue.$eq.$relativeTime) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + '$relativeTime can only be used with the $lt, $lte, $gt, and $gte operators' + ); } else { values.push(fieldName, fieldValue.$eq); patterns.push(`$${index}:name = $${index + 1}`); @@ -513,7 +523,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus } if (typeof fieldValue.$exists !== 'undefined') { - if (fieldValue.$exists) { + if (typeof fieldValue.$exists === 'object' && fieldValue.$exists.$relativeTime) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + '$relativeTime can only be used with the $lt, $lte, $gt, and $gte operators' + ); + } else if (fieldValue.$exists) { patterns.push(`$${index}:name IS NOT NULL`); } else { patterns.push(`$${index}:name IS NULL`); @@ -757,7 +772,7 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus Object.keys(ParseToPosgresComparator).forEach(cmp => { if (fieldValue[cmp] || fieldValue[cmp] === 0) { const pgComparator = ParseToPosgresComparator[cmp]; - const postgresValue = toPostgresValue(fieldValue[cmp]); + let postgresValue = toPostgresValue(fieldValue[cmp]); let constraintFieldName; if (fieldName.indexOf('.') >= 0) { let castType; @@ -775,6 +790,24 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus ? `CAST ((${transformDotField(fieldName)}) AS ${castType})` : transformDotField(fieldName); } else { + if (typeof postgresValue === 'object' && postgresValue.$relativeTime) { + if (schema.fields[fieldName].type !== 'Date') { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + '$relativeTime can only be used with Date field' + ); + } + const parserResult = Utils.relativeTimeToDate(postgresValue.$relativeTime); + if (parserResult.status === 'success') { + postgresValue = toPostgresValue(parserResult.result); + } else { + console.error('Error while parsing relative date', parserResult); + throw new Parse.Error( + Parse.Error.INVALID_JSON, + `bad $relativeTime (${postgresValue.$relativeTime}) value. ${parserResult.info}` + ); + } + } constraintFieldName = `$${index++}:name`; values.push(fieldName); } diff --git a/src/Utils.js b/src/Utils.js index e78d7ddd6c..c96be08495 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -200,6 +200,138 @@ class Utils { } } } + + /** + * Computes the relative date based on a string. + * @param {String} text The string to interpret the date from. + * @param {Date} now The date the string is comparing against. + * @returns {Object} The relative date object. + **/ + static relativeTimeToDate(text, now = new Date()) { + text = text.toLowerCase(); + let parts = text.split(' '); + + // Filter out whitespace + parts = parts.filter(part => part !== ''); + + const future = parts[0] === 'in'; + const past = parts[parts.length - 1] === 'ago'; + + if (!future && !past && text !== 'now') { + return { + status: 'error', + info: "Time should either start with 'in' or end with 'ago'", + }; + } + + if (future && past) { + return { + status: 'error', + info: "Time cannot have both 'in' and 'ago'", + }; + } + + // strip the 'ago' or 'in' + if (future) { + parts = parts.slice(1); + } else { + // past + parts = parts.slice(0, parts.length - 1); + } + + if (parts.length % 2 !== 0 && text !== 'now') { + return { + status: 'error', + info: 'Invalid time string. Dangling unit or number.', + }; + } + + const pairs = []; + while (parts.length) { + pairs.push([parts.shift(), parts.shift()]); + } + + let seconds = 0; + for (const [num, interval] of pairs) { + const val = Number(num); + if (!Number.isInteger(val)) { + return { + status: 'error', + info: `'${num}' is not an integer.`, + }; + } + + switch (interval) { + case 'yr': + case 'yrs': + case 'year': + case 'years': + seconds += val * 31536000; // 365 * 24 * 60 * 60 + break; + + case 'wk': + case 'wks': + case 'week': + case 'weeks': + seconds += val * 604800; // 7 * 24 * 60 * 60 + break; + + case 'd': + case 'day': + case 'days': + seconds += val * 86400; // 24 * 60 * 60 + break; + + case 'hr': + case 'hrs': + case 'hour': + case 'hours': + seconds += val * 3600; // 60 * 60 + break; + + case 'min': + case 'mins': + case 'minute': + case 'minutes': + seconds += val * 60; + break; + + case 'sec': + case 'secs': + case 'second': + case 'seconds': + seconds += val; + break; + + default: + return { + status: 'error', + info: `Invalid interval: '${interval}'`, + }; + } + } + + const milliseconds = seconds * 1000; + if (future) { + return { + status: 'success', + info: 'future', + result: new Date(now.valueOf() + milliseconds), + }; + } else if (past) { + return { + status: 'success', + info: 'past', + result: new Date(now.valueOf() - milliseconds), + }; + } else { + return { + status: 'success', + info: 'present', + result: new Date(now.valueOf()), + }; + } + } } module.exports = Utils; From acfdc54a06fd0e9e33bf2937507ce44d2e8e1b68 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 2 Jan 2022 00:11:48 +0000 Subject: [PATCH 35/83] chore(release): 5.0.0-alpha.14 [skip ci] # [5.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.13...5.0.0-alpha.14) (2022-01-02) ### Features * support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index e635c16fba..ebeefd38f7 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.13...5.0.0-alpha.14) (2022-01-02) + + +### Features + +* support relativeTime query constraint on Postgres ([#7747](https://github.com/parse-community/parse-server/issues/7747)) ([16b1b2a](https://github.com/parse-community/parse-server/commit/16b1b2a19714535ca805f2dbb3b561d8f6a519a7)) + # [5.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.12...5.0.0-alpha.13) (2021-12-08) diff --git a/package-lock.json b/package-lock.json index 38bf6a39a8..5f1beddb71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.13", + "version": "5.0.0-alpha.14", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4162381239..52d6caf52b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.13", + "version": "5.0.0-alpha.14", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From b106ffc994623a07741399e0f4a6d22c5640d24b Mon Sep 17 00:00:00 2001 From: Corey Date: Sat, 1 Jan 2022 19:45:00 -0500 Subject: [PATCH 36/83] ci: test server with PostGIS 3.2 (#7752) --- .github/workflows/ci.yml | 15 +++++++++------ CONTRIBUTING.md | 4 ++-- README.md | 8 ++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96ed13b0c8..2463901a91 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -187,14 +187,17 @@ jobs: - name: PostgreSQL 11, PostGIS 3.1 POSTGRES_IMAGE: postgis/postgis:11-3.1 NODE_VERSION: 16.13.0 - - name: PostgreSQL 12, PostGIS 3.1 - POSTGRES_IMAGE: postgis/postgis:12-3.1 + - name: PostgreSQL 11, PostGIS 3.2 + POSTGRES_IMAGE: postgis/postgis:11-3.2 NODE_VERSION: 16.13.0 - - name: PostgreSQL 13, PostGIS 3.1 - POSTGRES_IMAGE: postgis/postgis:13-3.1 + - name: PostgreSQL 12, PostGIS 3.2 + POSTGRES_IMAGE: postgis/postgis:12-3.2 NODE_VERSION: 16.13.0 - - name: PostgreSQL 14, PostGIS 3.1 - POSTGRES_IMAGE: postgis/postgis:14-3.1 + - name: PostgreSQL 13, PostGIS 3.2 + POSTGRES_IMAGE: postgis/postgis:13-3.2 + NODE_VERSION: 16.13.0 + - name: PostgreSQL 14, PostGIS 3.2 + POSTGRES_IMAGE: postgis/postgis:14-3.2 NODE_VERSION: 16.13.0 fail-fast: false name: ${{ matrix.name }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e620fbc78..1605c47ec3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,7 +154,7 @@ If your pull request introduces a change that may affect the storage or retrieva [PostGIS images (select one with v2.2 or higher) on docker dashboard](https://hub.docker.com/r/postgis/postgis) is based off of the official [postgres](https://registry.hub.docker.com/_/postgres/) image and will work out-of-the-box (as long as you create a user with the necessary extensions for each of your Parse databases; see below). To launch the compatible Postgres instance, copy and paste the following line into your shell: ``` -docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:13-3.1-alpine && sleep 20 && docker exec -it parse-postgres psql -U postgres -c 'CREATE DATABASE parse_server_postgres_adapter_test_database;' && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION pgcrypto; CREATE EXTENSION postgis;' -d parse_server_postgres_adapter_test_database && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis_topology;' -d parse_server_postgres_adapter_test_database +docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:13-3.2-alpine && sleep 20 && docker exec -it parse-postgres psql -U postgres -c 'CREATE DATABASE parse_server_postgres_adapter_test_database;' && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION pgcrypto; CREATE EXTENSION postgis;' -d parse_server_postgres_adapter_test_database && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis_topology;' -d parse_server_postgres_adapter_test_database ``` To stop the Postgres instance: @@ -162,7 +162,7 @@ To stop the Postgres instance: docker stop parse-postgres ``` -You can also use the [postgis/postgis:13-3.1-alpine](https://hub.docker.com/r/postgis/postgis) image in a Dockerfile and copy this [script](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) to the image by adding the following lines: +You can also use the [postgis/postgis:13-3.2-alpine](https://hub.docker.com/r/postgis/postgis) image in a Dockerfile and copy this [script](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) to the image by adding the following lines: ``` #Install additional scripts. These are run in abc order during initial start diff --git a/README.md b/README.md index f2ecce98ab..86d1247b0f 100644 --- a/README.md +++ b/README.md @@ -134,10 +134,10 @@ Parse Server is continuously tested with the most recent releases of PostgreSQL | Version | PostGIS Version | End-of-Life | Parse Server Support End | Compatible | |-------------|-----------------|---------------|--------------------------|------------| -| Postgres 11 | 3.0, 3.1 | November 2023 | April 2022 | ✅ Yes | -| Postgres 12 | 3.1 | November 2024 | April 2023 | ✅ Yes | -| Postgres 13 | 3.1 | November 2025 | April 2024 | ✅ Yes | -| Postgres 14 | 3.1 | November 2026 | April 2025 | ✅ Yes | +| Postgres 11 | 3.0, 3.1, 3.2 | November 2023 | April 2022 | ✅ Yes | +| Postgres 12 | 3.2 | November 2024 | April 2023 | ✅ Yes | +| Postgres 13 | 3.2 | November 2025 | April 2024 | ✅ Yes | +| Postgres 14 | 3.2 | November 2026 | April 2025 | ✅ Yes | ### Locally ```bash From 912edacb53c6cd9c05436918072896aaf4cf8107 Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 2 Jan 2022 08:59:00 -0500 Subject: [PATCH 37/83] test: make GraphQL server test more reliable (#7758) --- spec/ParseGraphQLServer.spec.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 58b26e4b65..d204886fe5 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2600,11 +2600,19 @@ describe('ParseGraphQLServer', () => { // "SecondaryObject:bBRgmzIRRM" < "SecondaryObject:nTMcuVbATY" true // base64("SecondaryObject:bBRgmzIRRM"") < base64(""SecondaryObject:nTMcuVbATY"") false // "U2Vjb25kYXJ5T2JqZWN0OmJCUmdteklSUk0=" < "U2Vjb25kYXJ5T2JqZWN0Om5UTWN1VmJBVFk=" false + const originalIds = [getSecondaryObjectsResult.data.secondaryObject2.objectId, + getSecondaryObjectsResult.data.secondaryObject4.objectId]; expect( findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.objectId - ).toBeLessThan( + ).not.toBe( findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.objectId ); + expect( + originalIds.includes(findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.objectId) + ).toBeTrue(); + expect( + originalIds.includes(findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.objectId) + ).toBeTrue(); const createPrimaryObjectResult = await apolloClient.mutate({ mutation: gql` From caf4a2341f554b28e3918c53e7e897a3ca47bf8b Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 2 Jan 2022 09:25:43 -0500 Subject: [PATCH 38/83] feat: support `postgresql` protocol in database URI (#7757) --- spec/PostgresInitOptions.spec.js | 92 ++++++++++++----------------- spec/PostgresStorageAdapter.spec.js | 11 +++- src/Controllers/index.js | 1 + 3 files changed, 49 insertions(+), 55 deletions(-) diff --git a/spec/PostgresInitOptions.spec.js b/spec/PostgresInitOptions.spec.js index 069d5a6437..760240734d 100644 --- a/spec/PostgresInitOptions.spec.js +++ b/spec/PostgresInitOptions.spec.js @@ -4,8 +4,7 @@ const PostgresStorageAdapter = require('../lib/Adapters/Storage/Postgres/Postgre const postgresURI = process.env.PARSE_SERVER_TEST_DATABASE_URI || 'postgres://localhost:5432/parse_server_postgres_adapter_test_database'; -const ParseServer = require('../lib/index'); -const express = require('express'); + //public schema const databaseOptions1 = { initOptions: { @@ -24,72 +23,57 @@ const GameScore = Parse.Object.extend({ className: 'GameScore', }); -function createParseServer(options) { - return new Promise((resolve, reject) => { - const parseServer = new ParseServer.default( - Object.assign({}, defaultConfiguration, options, { - serverURL: 'http://localhost:12668/parse', - serverStartComplete: error => { - if (error) { - reject(error); - } else { - expect(Parse.applicationId).toEqual('test'); - const app = express(); - app.use('/parse', parseServer.app); - - const server = app.listen(12668); - Parse.serverURL = 'http://localhost:12668/parse'; - resolve(server); - } - }, - }) - ); - }); -} - describe_only_db('postgres')('Postgres database init options', () => { - let server; - - afterAll(done => { - if (server) { - Parse.serverURL = 'http://localhost:8378/1'; - server.close(done); - } - }); - it('should create server with public schema databaseOptions', done => { + it('should create server with public schema databaseOptions', async () => { const adapter = new PostgresStorageAdapter({ uri: postgresURI, collectionPrefix: 'test_', databaseOptions: databaseOptions1, }); + await reconfigureServer({ + databaseAdapter: adapter, + }); + const score = new GameScore({ + score: 1337, + playerName: 'Sean Plott', + cheatMode: false, + }); + await score.save(); + }); - createParseServer({ databaseAdapter: adapter }) - .then(newServer => { - server = newServer; - const score = new GameScore({ - score: 1337, - playerName: 'Sean Plott', - cheatMode: false, - }); - return score.save(); - }) - .then(async () => { - await reconfigureServer(); - done(); - }, done.fail); + it('should create server using postgresql uri with public schema databaseOptions', async () => { + const postgresURI2 = new URL(postgresURI); + postgresURI2.protocol = 'postgresql:'; + const adapter = new PostgresStorageAdapter({ + uri: postgresURI2.toString(), + collectionPrefix: 'test_', + databaseOptions: databaseOptions1, + }); + await reconfigureServer({ + databaseAdapter: adapter, + }); + const score = new GameScore({ + score: 1337, + playerName: 'Sean Plott', + cheatMode: false, + }); + await score.save(); }); - it('should fail to create server if schema databaseOptions does not exist', done => { + it('should fail to create server if schema databaseOptions does not exist', async () => { const adapter = new PostgresStorageAdapter({ uri: postgresURI, collectionPrefix: 'test_', databaseOptions: databaseOptions2, }); - - createParseServer({ databaseAdapter: adapter }).then(done.fail, async () => { - await reconfigureServer(); - done(); - }); + try { + await reconfigureServer({ + databaseAdapter: adapter, + }); + fail("Should have thrown error"); + } catch(error) { + expect(error).toBeDefined(); + } }); }); diff --git a/spec/PostgresStorageAdapter.spec.js b/spec/PostgresStorageAdapter.spec.js index dfb6bf4100..769aad74c5 100644 --- a/spec/PostgresStorageAdapter.spec.js +++ b/spec/PostgresStorageAdapter.spec.js @@ -555,7 +555,7 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => { }, classLevelPermissions: undefined, }); - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise(resolve => setTimeout(resolve, 2000)); expect(adapter._onchange).toHaveBeenCalled(); }); }); @@ -567,4 +567,13 @@ describe_only_db('postgres')('PostgresStorageAdapter shutdown', () => { adapter.handleShutdown(); expect(adapter._client.$pool.ending).toEqual(true); }); + + it('handleShutdown, close connection of postgresql uri', () => { + const databaseURI2 = new URL(databaseURI); + databaseURI2.protocol = 'postgresql:'; + const adapter = new PostgresStorageAdapter({ uri: databaseURI2.toString() }); + expect(adapter._client.$pool.ending).toEqual(false); + adapter.handleShutdown(); + expect(adapter._client.$pool.ending).toEqual(true); + }); }); diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 89dc79c232..67f90a8edf 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -227,6 +227,7 @@ export function getDatabaseAdapter(databaseURI, collectionPrefix, databaseOption } switch (protocol) { case 'postgres:': + case 'postgresql:': return new PostgresStorageAdapter({ uri: databaseURI, collectionPrefix, From 75b9a56e0a4f2fd9e438eaaf99f5d2d94fb580a8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 2 Jan 2022 14:26:36 +0000 Subject: [PATCH 39/83] chore(release): 5.0.0-alpha.15 [skip ci] # [5.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.14...5.0.0-alpha.15) (2022-01-02) ### Features * support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index ebeefd38f7..15ee62549a 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.14...5.0.0-alpha.15) (2022-01-02) + + +### Features + +* support `postgresql` protocol in database URI ([#7757](https://github.com/parse-community/parse-server/issues/7757)) ([caf4a23](https://github.com/parse-community/parse-server/commit/caf4a2341f554b28e3918c53e7e897a3ca47bf8b)) + # [5.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.13...5.0.0-alpha.14) (2022-01-02) diff --git a/package-lock.json b/package-lock.json index 5f1beddb71..ca59098e15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.14", + "version": "5.0.0-alpha.15", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 52d6caf52b..30389b671e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.14", + "version": "5.0.0-alpha.15", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 7af5de4b987ce7a7f665d7aa889f2939f755599e Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 2 Jan 2022 09:51:49 -0500 Subject: [PATCH 40/83] test: improve PushController tests (#7760) --- spec/PushController.spec.js | 74 ++++++++++++------------------------- 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/spec/PushController.spec.js b/spec/PushController.spec.js index 4626b5e0a7..49613214f5 100644 --- a/spec/PushController.spec.js +++ b/spec/PushController.spec.js @@ -562,11 +562,7 @@ describe('PushController', () => { }); const pushStatusId = await sendPush(payload, {}, config, auth); // it is enqueued so it can take time - await new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 1000); - }); + await sleep(1000); Parse.serverURL = 'http://localhost:8378/1'; // GOOD url const result = await Parse.Push.getPushStatus(pushStatusId); expect(result).toBeDefined(); @@ -767,7 +763,7 @@ describe('PushController', () => { }); }); - it('should not schedule push when not configured', done => { + it('should not schedule push when not configured', async () => { const config = Config.get(Parse.applicationId); const auth = { isMaster: true, @@ -800,33 +796,20 @@ describe('PushController', () => { installations.push(installation); } - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, - }) - .then(() => { - return Parse.Object.saveAll(installations) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => new Promise(resolve => setTimeout(resolve, 300))); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }).then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('status')).not.toBe('scheduled'); - done(); - }); - }) - .catch(err => { - console.error(err); - fail('should not fail'); - done(); - }); + }); + await Parse.Object.saveAll(installations); + await pushController.sendPush(payload, {}, config, auth); + await sleep(1000); + const query = new Parse.Query('_PushStatus'); + const results = await query.find({ useMasterKey: true }); + expect(results.length).toBe(1); + const pushStatus = results[0]; + expect(pushStatus.get('status')).not.toBe('scheduled'); }); - it('should schedule push when configured', done => { + it('should schedule push when configured', async () => { const auth = { isMaster: true, }; @@ -866,28 +849,19 @@ describe('PushController', () => { installation.set('deviceType', 'ios'); installations.push(installation); } - reconfigureServer({ + await reconfigureServer({ push: { adapter: pushAdapter }, scheduledPush: true, - }) - .then(() => { - const config = Config.get(Parse.applicationId); - return Parse.Object.saveAll(installations) - .then(() => { - return pushController.sendPush(payload, {}, config, auth); - }) - .then(() => new Promise(resolve => setTimeout(resolve, 300))); - }) - .then(() => { - const query = new Parse.Query('_PushStatus'); - return query.find({ useMasterKey: true }).then(results => { - expect(results.length).toBe(1); - const pushStatus = results[0]; - expect(pushStatus.get('status')).toBe('scheduled'); - }); - }) - .then(done) - .catch(done.err); + }); + const config = Config.get(Parse.applicationId); + await Parse.Object.saveAll(installations); + await pushController.sendPush(payload, {}, config, auth); + await sleep(1000); + const query = new Parse.Query('_PushStatus'); + const results = await query.find({ useMasterKey: true }); + expect(results.length).toBe(1); + const pushStatus = results[0]; + expect(pushStatus.get('status')).toBe('scheduled'); }); it('should not enqueue push when device token is not set', async () => { From 5e363eae443f32444ba510113432ce4e32b9d718 Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 2 Jan 2022 12:43:12 -0500 Subject: [PATCH 41/83] refactor: remove unnecessary error checking in PostgresAdapter (#7761) --- .../Postgres/PostgresStorageAdapter.js | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index de5712b79d..f789952e9e 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -15,7 +15,6 @@ const PostgresRelationDoesNotExistError = '42P01'; const PostgresDuplicateRelationError = '42P07'; const PostgresDuplicateColumnError = '42701'; const PostgresMissingColumnError = '42703'; -const PostgresDuplicateObjectError = '42710'; const PostgresUniqueIndexViolationError = '23505'; const logger = require('../../../logger'); @@ -906,15 +905,7 @@ export class PostgresStorageAdapter implements StorageAdapter { 'CREATE TABLE IF NOT EXISTS "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )' ) .catch(error => { - if ( - error.code === PostgresDuplicateRelationError || - error.code === PostgresUniqueIndexViolationError || - error.code === PostgresDuplicateObjectError - ) { - // Table already exists, must have been created by a different request. Ignore error. - } else { - throw error; - } + throw error; }); } @@ -2450,23 +2441,7 @@ export class PostgresStorageAdapter implements StorageAdapter { : fieldNames.map((fieldName, index) => `$${index + 3}:name`); const qs = `CREATE INDEX IF NOT EXISTS $1:name ON $2:name (${constraintPatterns.join()})`; await conn.none(qs, [indexNameOptions.name, className, ...fieldNames]).catch(error => { - if ( - error.code === PostgresDuplicateRelationError && - error.message.includes(indexNameOptions.name) - ) { - // Index already exists. Ignore error. - } else if ( - error.code === PostgresUniqueIndexViolationError && - error.message.includes(indexNameOptions.name) - ) { - // Cast the error into the proper parse error - throw new Parse.Error( - Parse.Error.DUPLICATE_VALUE, - 'A duplicate value for a field with unique values was provided' - ); - } else { - throw error; - } + throw error; }); } } From 0c3feaaa1751964c0db89f25674935c3354b1538 Mon Sep 17 00:00:00 2001 From: Corey Date: Sun, 2 Jan 2022 13:25:53 -0500 Subject: [PATCH 42/83] feat: add Idempotency to Postgres (#7750) --- README.md | 21 +++++++- spec/Idempotency.spec.js | 35 +++++++++++-- spec/PostgresStorageAdapter.spec.js | 11 ++++ .../Postgres/PostgresStorageAdapter.js | 52 +++++++++++++++++-- src/Controllers/DatabaseController.js | 39 +++++++++----- src/Controllers/index.js | 4 +- src/middlewares.js | 3 +- 7 files changed, 139 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 86d1247b0f..7b507e9c80 100644 --- a/README.md +++ b/README.md @@ -525,9 +525,26 @@ let api = new ParseServer({ | `idempotencyOptions.paths` | yes | `Array` | `[]` | `.*` (all paths, includes the examples below),
`functions/.*` (all functions),
`jobs/.*` (all jobs),
`classes/.*` (all classes),
`functions/.*` (all functions),
`users` (user creation / update),
`installations` (installation creation / update) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_PATHS | An array of path patterns that have to match the request path for request deduplication to be enabled. The mount path must not be included, for example to match the request path `/parse/functions/myFunction` specify the path pattern `functions/myFunction`. A trailing slash of the request path is ignored, for example the path pattern `functions/myFunction` matches both `/parse/functions/myFunction` and `/parse/functions/myFunction/`. | | `idempotencyOptions.ttl` | yes | `Integer` | `300` | `60` (60 seconds) | PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_TTL | The duration in seconds after which a request record is discarded from the database. Duplicate requests due to network issues can be expected to arrive within milliseconds up to several seconds. This value must be greater than `0`. | -### Notes +### Postgres + +To use this feature in Postgres, you will need to create a cron job using [pgAdmin](https://www.pgadmin.org/docs/pgadmin4/development/pgagent_jobs.html) or similar to call the Postgres function `idempotency_delete_expired_records()` that deletes expired idempotency records. You can find an example script below. Make sure the script has the same privileges to log into Postgres as Parse Server. + +```bash +#!/bin/bash + +set -e +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL + SELECT idempotency_delete_expired_records(); +EOSQL -- This feature is currently only available for MongoDB and not for Postgres. +exec "$@" +``` + +Assuming the script above is named, `parse_idempotency_delete_expired_records.sh`, a cron job that runs the script every 2 minutes may look like: + +```bash +2 * * * * /root/parse_idempotency_delete_expired_records.sh >/dev/null 2>&1 +``` ## Localization diff --git a/spec/Idempotency.spec.js b/spec/Idempotency.spec.js index c2ef8665b7..85fa8a65fa 100644 --- a/spec/Idempotency.spec.js +++ b/spec/Idempotency.spec.js @@ -6,11 +6,14 @@ const rest = require('../lib/rest'); const auth = require('../lib/Auth'); const uuid = require('uuid'); -describe_only_db('mongo')('Idempotency', () => { +describe('Idempotency', () => { // Parameters /** Enable TTL expiration simulated by removing entry instead of waiting for MongoDB TTL monitor which runs only every 60s, so it can take up to 119s until entry removal - ain't nobody got time for that */ const SIMULATE_TTL = true; + const ttl = 2; + const maxTimeOut = 4000; + // Helpers async function deleteRequestEntry(reqId) { const config = Config.get(Parse.applicationId); @@ -38,9 +41,10 @@ describe_only_db('mongo')('Idempotency', () => { } await setup({ paths: ['functions/.*', 'jobs/.*', 'classes/.*', 'users', 'installations'], - ttl: 30, + ttl: ttl, }); }); + // Tests it('should enforce idempotency for cloud code function', async () => { let counter = 0; @@ -56,7 +60,7 @@ describe_only_db('mongo')('Idempotency', () => { 'X-Parse-Request-Id': 'abc-123', }, }; - expect(Config.get(Parse.applicationId).idempotencyOptions.ttl).toBe(30); + expect(Config.get(Parse.applicationId).idempotencyOptions.ttl).toBe(ttl); await request(params); await request(params).then(fail, e => { expect(e.status).toEqual(400); @@ -83,12 +87,35 @@ describe_only_db('mongo')('Idempotency', () => { if (SIMULATE_TTL) { await deleteRequestEntry('abc-123'); } else { - await new Promise(resolve => setTimeout(resolve, 130000)); + await new Promise(resolve => setTimeout(resolve, maxTimeOut)); } await expectAsync(request(params)).toBeResolved(); expect(counter).toBe(2); }); + it_only_db('postgres')('should delete request entry when postgress ttl function is called', async () => { + const client = Config.get(Parse.applicationId).database.adapter._client; + let counter = 0; + Parse.Cloud.define('myFunction', () => { + counter++; + }); + const params = { + method: 'POST', + url: 'http://localhost:8378/1/functions/myFunction', + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Master-Key': Parse.masterKey, + 'X-Parse-Request-Id': 'abc-123', + }, + }; + await expectAsync(request(params)).toBeResolved(); + await expectAsync(request(params)).toBeRejected(); + await new Promise(resolve => setTimeout(resolve, maxTimeOut)); + await client.one('SELECT idempotency_delete_expired_records()'); + await expectAsync(request(params)).toBeResolved(); + expect(counter).toBe(2); + }); + it('should enforce idempotency for cloud code jobs', async () => { let counter = 0; Parse.Cloud.job('myJob', () => { diff --git a/spec/PostgresStorageAdapter.spec.js b/spec/PostgresStorageAdapter.spec.js index 769aad74c5..5673d6bc70 100644 --- a/spec/PostgresStorageAdapter.spec.js +++ b/spec/PostgresStorageAdapter.spec.js @@ -558,6 +558,17 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => { await new Promise(resolve => setTimeout(resolve, 2000)); expect(adapter._onchange).toHaveBeenCalled(); }); + + it('Idempotency class should have function', async () => { + await reconfigureServer(); + const adapter = Config.get('test').database.adapter; + const client = adapter._client; + const qs = "SELECT format('%I.%I(%s)', ns.nspname, p.proname, oidvectortypes(p.proargtypes)) FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) WHERE p.proname = 'idempotency_delete_expired_records'"; + const foundFunction = await client.one(qs); + expect(foundFunction.format).toBe("public.idempotency_delete_expired_records()"); + await adapter.deleteIdempotencyFunction(); + await client.none(qs); + }); }); describe_only_db('postgres')('PostgresStorageAdapter shutdown', () => { diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index f789952e9e..7477270a3d 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -2440,9 +2440,55 @@ export class PostgresStorageAdapter implements StorageAdapter { ? fieldNames.map((fieldName, index) => `lower($${index + 3}:name) varchar_pattern_ops`) : fieldNames.map((fieldName, index) => `$${index + 3}:name`); const qs = `CREATE INDEX IF NOT EXISTS $1:name ON $2:name (${constraintPatterns.join()})`; - await conn.none(qs, [indexNameOptions.name, className, ...fieldNames]).catch(error => { - throw error; - }); + const setIdempotencyFunction = options.setIdempotencyFunction !== undefined ? options.setIdempotencyFunction : false; + if (setIdempotencyFunction) { + await this.ensureIdempotencyFunctionExists(options); + } + await conn.none(qs, [indexNameOptions.name, className, ...fieldNames]) + .catch(error => { + if ( + error.code === PostgresDuplicateRelationError && + error.message.includes(indexNameOptions.name) + ) { + // Index already exists. Ignore error. + } else if ( + error.code === PostgresUniqueIndexViolationError && + error.message.includes(indexNameOptions.name) + ) { + // Cast the error into the proper parse error + throw new Parse.Error( + Parse.Error.DUPLICATE_VALUE, + 'A duplicate value for a field with unique values was provided' + ); + } else { + throw error; + } + }); + } + + async deleteIdempotencyFunction( + options?: Object = {} + ): Promise { + const conn = options.conn !== undefined ? options.conn : this._client; + const qs = 'DROP FUNCTION IF EXISTS idempotency_delete_expired_records()'; + return conn + .none(qs) + .catch(error => { + throw error; + }); + } + + async ensureIdempotencyFunctionExists( + options?: Object = {} + ): Promise { + const conn = options.conn !== undefined ? options.conn : this._client; + const ttlOptions = options.ttl !== undefined ? `${options.ttl} seconds` : '60 seconds'; + const qs = 'CREATE OR REPLACE FUNCTION idempotency_delete_expired_records() RETURNS void LANGUAGE plpgsql AS $$ BEGIN DELETE FROM "_Idempotency" WHERE expire < NOW() - INTERVAL $1; END; $$;'; + return conn + .none(qs, [ttlOptions]) + .catch(error => { + throw error; + }); } } diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 42273b6990..2c313f83b4 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -14,6 +14,7 @@ import logger from '../logger'; import * as SchemaController from './SchemaController'; import { StorageAdapter } from '../Adapters/Storage/StorageAdapter'; import MongoStorageAdapter from '../Adapters/Storage/Mongo/MongoStorageAdapter'; +import PostgresStorageAdapter from '../Adapters/Storage/Postgres/PostgresStorageAdapter'; import SchemaCache from '../Adapters/Cache/SchemaCache'; import type { LoadSchemaOptions } from './types'; import type { QueryOptions, FullQueryOptions } from '../Adapters/Storage/StorageAdapter'; @@ -394,12 +395,14 @@ const relationSchema = { class DatabaseController { adapter: StorageAdapter; + idempotencyOptions: any; schemaCache: any; schemaPromise: ?Promise; _transactionalSession: ?any; - constructor(adapter: StorageAdapter) { + constructor(adapter: StorageAdapter, idempotencyOptions?: Object = {}) { this.adapter = adapter; + this.idempotencyOptions = idempotencyOptions; // We don't want a mutable this.schema, because then you could have // one request that uses different schemas for different parts of // it. Instead, use loadSchema to get a schema. @@ -1713,9 +1716,7 @@ class DatabaseController { }; await this.loadSchema().then(schema => schema.enforceClassExists('_User')); await this.loadSchema().then(schema => schema.enforceClassExists('_Role')); - if (this.adapter instanceof MongoStorageAdapter) { - await this.loadSchema().then(schema => schema.enforceClassExists('_Idempotency')); - } + await this.loadSchema().then(schema => schema.enforceClassExists('_Idempotency')); await this.adapter.ensureUniqueness('_User', requiredUserFields, ['username']).catch(error => { logger.warn('Unable to ensure uniqueness for usernames: ', error); @@ -1751,18 +1752,28 @@ class DatabaseController { logger.warn('Unable to ensure uniqueness for role name: ', error); throw error; }); - if (this.adapter instanceof MongoStorageAdapter) { - await this.adapter - .ensureUniqueness('_Idempotency', requiredIdempotencyFields, ['reqId']) - .catch(error => { - logger.warn('Unable to ensure uniqueness for idempotency request ID: ', error); - throw error; - }); - await this.adapter - .ensureIndex('_Idempotency', requiredIdempotencyFields, ['expire'], 'ttl', false, { + await this.adapter + .ensureUniqueness('_Idempotency', requiredIdempotencyFields, ['reqId']) + .catch(error => { + logger.warn('Unable to ensure uniqueness for idempotency request ID: ', error); + throw error; + }); + + const isMongoAdapter = this.adapter instanceof MongoStorageAdapter; + const isPostgresAdapter = this.adapter instanceof PostgresStorageAdapter; + if (isMongoAdapter || isPostgresAdapter) { + let options = {}; + if (isMongoAdapter) { + options = { ttl: 0, - }) + }; + } else if (isPostgresAdapter) { + options = this.idempotencyOptions; + options.setIdempotencyFunction = true; + } + await this.adapter + .ensureIndex('_Idempotency', requiredIdempotencyFields, ['expire'], 'ttl', false, options) .catch(error => { logger.warn('Unable to create TTL index for idempotency expire date: ', error); throw error; diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 67f90a8edf..71ab5ef486 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -143,7 +143,7 @@ export function getLiveQueryController(options: ParseServerOptions): LiveQueryCo } export function getDatabaseController(options: ParseServerOptions): DatabaseController { - const { databaseURI, collectionPrefix, databaseOptions } = options; + const { databaseURI, collectionPrefix, databaseOptions, idempotencyOptions } = options; let { databaseAdapter } = options; if ( (databaseOptions || @@ -157,7 +157,7 @@ export function getDatabaseController(options: ParseServerOptions): DatabaseCont } else { databaseAdapter = loadAdapter(databaseAdapter); } - return new DatabaseController(databaseAdapter); + return new DatabaseController(databaseAdapter, idempotencyOptions); } export function getHooksController( diff --git a/src/middlewares.js b/src/middlewares.js index 88de107264..e749d0507a 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -6,6 +6,7 @@ import ClientSDK from './ClientSDK'; import defaultLogger from './logger'; import rest from './rest'; import MongoStorageAdapter from './Adapters/Storage/Mongo/MongoStorageAdapter'; +import PostgresStorageAdapter from './Adapters/Storage/Postgres/PostgresStorageAdapter'; 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'; @@ -431,7 +432,7 @@ export function promiseEnforceMasterKeyAccess(request) { */ export function promiseEnsureIdempotency(req) { // Enable feature only for MongoDB - if (!(req.config.database.adapter instanceof MongoStorageAdapter)) { + if (!((req.config.database.adapter instanceof MongoStorageAdapter) || (req.config.database.adapter instanceof PostgresStorageAdapter))) { return Promise.resolve(); } // Get parameters From 410a1c74fbc2d3c17c7ced8008ca3de8a5358b0e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 2 Jan 2022 18:26:55 +0000 Subject: [PATCH 43/83] chore(release): 5.0.0-alpha.16 [skip ci] # [5.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.15...5.0.0-alpha.16) (2022-01-02) ### Features * add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 15ee62549a..a3b6cd12d5 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.15...5.0.0-alpha.16) (2022-01-02) + + +### Features + +* add Idempotency to Postgres ([#7750](https://github.com/parse-community/parse-server/issues/7750)) ([0c3feaa](https://github.com/parse-community/parse-server/commit/0c3feaaa1751964c0db89f25674935c3354b1538)) + # [5.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.14...5.0.0-alpha.15) (2022-01-02) diff --git a/package-lock.json b/package-lock.json index ca59098e15..fb3b940260 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.15", + "version": "5.0.0-alpha.16", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 30389b671e..40e47acc65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.15", + "version": "5.0.0-alpha.16", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From d05fb9f2fab431c4880c51b5d8e997a924c752df Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Mon, 3 Jan 2022 14:56:55 +0000 Subject: [PATCH 44/83] refactor: upgrade graphql from 15.7.0 to 15.7.1 (#7706) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb3b940260..2bfd0ece4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7448,9 +7448,9 @@ "dev": true }, "graphql": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.7.0.tgz", - "integrity": "sha512-1jvUsS5mSzcgXLTQNQyrP7eKkBZW+HUnmx2LYSnfvkyseVpij8wwO/sFBGgxbkZ+zzFwYQxrHsOana5oMXmMxg==" + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.7.1.tgz", + "integrity": "sha512-x34S6gC0/peBZnlK60zCJox/d45A7p6At9oN9EPA3qhoIAlR4LNZmXRLkICBckwwTMJzVdA8cx3QIQZMOl606A==" }, "graphql-extensions": { "version": "0.15.0", diff --git a/package.json b/package.json index 40e47acc65..514f0be0eb 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "deepcopy": "2.1.0", "express": "4.17.1", "follow-redirects": "1.14.6", - "graphql": "15.7.0", + "graphql": "15.7.1", "graphql-list-fields": "2.0.2", "graphql-relay": "0.7.0", "graphql-tag": "2.12.6", From a43638f3003f12793f72b7aa633c219fc061adc5 Mon Sep 17 00:00:00 2001 From: Corey Date: Mon, 3 Jan 2022 18:49:43 -0500 Subject: [PATCH 45/83] test: improve transaction tests to use async/await (#7759) --- spec/ParseServerRESTController.spec.js | 321 +++++++++---------------- spec/batch.spec.js | 175 +++++++------- 2 files changed, 200 insertions(+), 296 deletions(-) diff --git a/spec/ParseServerRESTController.spec.js b/spec/ParseServerRESTController.spec.js index 90fe383257..1b136808b9 100644 --- a/spec/ParseServerRESTController.spec.js +++ b/spec/ParseServerRESTController.spec.js @@ -15,35 +15,18 @@ describe('ParseServerRESTController', () => { ); }); - it('should handle a get request', done => { - RESTController.request('GET', '/classes/MyObject').then( - res => { - expect(res.results.length).toBe(0); - done(); - }, - err => { - console.log(err); - jfail(err); - done(); - } - ); + it('should handle a get request', async () => { + const res = await RESTController.request('GET', '/classes/MyObject'); + expect(res.results.length).toBe(0); }); - it('should handle a get request with full serverURL mount path', done => { - RESTController.request('GET', '/1/classes/MyObject').then( - res => { - expect(res.results.length).toBe(0); - done(); - }, - err => { - jfail(err); - done(); - } - ); + it('should handle a get request with full serverURL mount path', async () => { + const res = await RESTController.request('GET', '/1/classes/MyObject'); + expect(res.results.length).toBe(0); }); - it('should handle a POST batch without transaction', done => { - RESTController.request('POST', 'batch', { + it('should handle a POST batch without transaction', async () => { + const res = await RESTController.request('POST', 'batch', { requests: [ { method: 'GET', @@ -59,20 +42,12 @@ describe('ParseServerRESTController', () => { path: '/classes/MyObject', }, ], - }).then( - res => { - expect(res.length).toBe(3); - done(); - }, - err => { - jfail(err); - done(); - } - ); + }); + expect(res.length).toBe(3); }); - it('should handle a POST batch with transaction=false', done => { - RESTController.request('POST', 'batch', { + it('should handle a POST batch with transaction=false', async () => { + const res = await RESTController.request('POST', 'batch', { requests: [ { method: 'GET', @@ -89,16 +64,8 @@ describe('ParseServerRESTController', () => { }, ], transaction: false, - }).then( - res => { - expect(res.length).toBe(3); - done(); - }, - err => { - jfail(err); - done(); - } - ); + }); + expect(res.length).toBe(3); }); it('should handle response status', async () => { @@ -186,54 +153,43 @@ describe('ParseServerRESTController', () => { } }); - it('should handle a batch request with transaction = true', async done => { - await reconfigureServer(); + it('should handle a batch request with transaction = true', async () => { const myObject = new Parse.Object('MyObject'); // This is important because transaction only works on pre-existing collections - myObject - .save() - .then(() => { - return myObject.destroy(); - }) - .then(() => { - spyOn(databaseAdapter, 'createObject').and.callThrough(); - - return RESTController.request('POST', 'batch', { - requests: [ - { - method: 'POST', - path: '/1/classes/MyObject', - body: { key: 'value1' }, - }, - { - method: 'POST', - path: '/1/classes/MyObject', - body: { key: 'value2' }, - }, - ], - transaction: true, - }).then(response => { - expect(response.length).toEqual(2); - expect(response[0].success.objectId).toBeDefined(); - expect(response[0].success.createdAt).toBeDefined(); - expect(response[1].success.objectId).toBeDefined(); - expect(response[1].success.createdAt).toBeDefined(); - const query = new Parse.Query('MyObject'); - return query.find().then(results => { - expect(databaseAdapter.createObject.calls.count() % 2).toBe(0); - for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) { - expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe( - databaseAdapter.createObject.calls.argsFor(i + 1)[3] - ); - } - expect(results.map(result => result.get('key')).sort()).toEqual([ - 'value1', - 'value2', - ]); - done(); - }); - }); - }) - .catch(done.fail); + await myObject.save(); + await myObject.destroy(); + spyOn(databaseAdapter, 'createObject').and.callThrough(); + const response = await RESTController.request('POST', 'batch', { + requests: [ + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value2' }, + }, + ], + transaction: true, + }); + expect(response.length).toEqual(2); + expect(response[0].success.objectId).toBeDefined(); + expect(response[0].success.createdAt).toBeDefined(); + expect(response[1].success.objectId).toBeDefined(); + expect(response[1].success.createdAt).toBeDefined(); + const query = new Parse.Query('MyObject'); + const results = await query.find(); + expect(databaseAdapter.createObject.calls.count() % 2).toBe(0); + for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) { + expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe( + databaseAdapter.createObject.calls.argsFor(i + 1)[3] + ); + } + expect(results.map(result => result.get('key')).sort()).toEqual([ + 'value1', + 'value2', + ]); }); it('should not save anything when one operation fails in a transaction', async () => { @@ -560,21 +516,11 @@ describe('ParseServerRESTController', () => { }); } - it('should handle a POST request', done => { - RESTController.request('POST', '/classes/MyObject', { key: 'value' }) - .then(() => { - return RESTController.request('GET', '/classes/MyObject'); - }) - .then(res => { - expect(res.results.length).toBe(1); - expect(res.results[0].key).toEqual('value'); - done(); - }) - .catch(err => { - console.log(err); - jfail(err); - done(); - }); + it('should handle a POST request', async () => { + await RESTController.request('POST', '/classes/MyObject', { key: 'value' }); + const res = await RESTController.request('GET', '/classes/MyObject'); + expect(res.results.length).toBe(1); + expect(res.results[0].key).toEqual('value'); }); it('should handle a POST request with context', async () => { @@ -593,125 +539,76 @@ describe('ParseServerRESTController', () => { ); }); - it('ensures sessionTokens are properly handled', done => { - let userId; - Parse.User.signUp('user', 'pass') - .then(user => { - userId = user.id; - const sessionToken = user.getSessionToken(); - return RESTController.request('GET', '/users/me', undefined, { - sessionToken, - }); - }) - .then(res => { - // Result is in JSON format - expect(res.objectId).toEqual(userId); - done(); - }) - .catch(err => { - console.log(err); - jfail(err); - done(); - }); + it('ensures sessionTokens are properly handled', async () => { + const user = await Parse.User.signUp('user', 'pass'); + const sessionToken = user.getSessionToken(); + const res = await RESTController.request('GET', '/users/me', undefined, { + sessionToken, + }); + // Result is in JSON format + expect(res.objectId).toEqual(user.id); }); - it('ensures masterKey is properly handled', done => { - let userId; - Parse.User.signUp('user', 'pass') - .then(user => { - userId = user.id; - return Parse.User.logOut().then(() => { - return RESTController.request('GET', '/classes/_User', undefined, { - useMasterKey: true, - }); - }); - }) - .then( - res => { - expect(res.results.length).toBe(1); - expect(res.results[0].objectId).toEqual(userId); - done(); - }, - err => { - jfail(err); - done(); - } - ); + it('ensures masterKey is properly handled', async () => { + const user = await Parse.User.signUp('user', 'pass'); + const userId = user.id; + await Parse.User.logOut(); + const res = await RESTController.request('GET', '/classes/_User', undefined, { + useMasterKey: true, + }); + expect(res.results.length).toBe(1); + expect(res.results[0].objectId).toEqual(userId); }); - it('ensures no user is created when passing an empty username', done => { - RESTController.request('POST', '/classes/_User', { - username: '', - password: 'world', - }).then( - () => { - jfail(new Error('Success callback should not be called when passing an empty username.')); - done(); - }, - err => { - expect(err.code).toBe(Parse.Error.USERNAME_MISSING); - expect(err.message).toBe('bad or missing username'); - done(); - } - ); + it('ensures no user is created when passing an empty username', async () => { + try { + await RESTController.request('POST', '/classes/_User', { + username: '', + password: 'world', + }); + fail('Success callback should not be called when passing an empty username.'); + } catch (err) { + expect(err.code).toBe(Parse.Error.USERNAME_MISSING); + expect(err.message).toBe('bad or missing username'); + } }); - it('ensures no user is created when passing an empty password', done => { - RESTController.request('POST', '/classes/_User', { - username: 'hello', - password: '', - }).then( - () => { - jfail(new Error('Success callback should not be called when passing an empty password.')); - done(); - }, - err => { - expect(err.code).toBe(Parse.Error.PASSWORD_MISSING); - expect(err.message).toBe('password is required'); - done(); - } - ); + it('ensures no user is created when passing an empty password', async () => { + try { + await RESTController.request('POST', '/classes/_User', { + username: 'hello', + password: '', + }); + fail('Success callback should not be called when passing an empty password.'); + } catch (err) { + expect(err.code).toBe(Parse.Error.PASSWORD_MISSING); + expect(err.message).toBe('password is required'); + } }); - it('ensures no session token is created on creating users', done => { - RESTController.request('POST', '/classes/_User', { + it('ensures no session token is created on creating users', async () => { + const user = await RESTController.request('POST', '/classes/_User', { username: 'hello', password: 'world', - }) - .then(user => { - expect(user.sessionToken).toBeUndefined(); - const query = new Parse.Query('_Session'); - return query.find({ useMasterKey: true }); - }) - .then(sessions => { - expect(sessions.length).toBe(0); - done(); - }, done.fail); + }); + expect(user.sessionToken).toBeUndefined(); + const query = new Parse.Query('_Session'); + const sessions = await query.find({ useMasterKey: true }); + expect(sessions.length).toBe(0); }); - it('ensures a session token is created when passing installationId != cloud', done => { - RESTController.request( + it('ensures a session token is created when passing installationId != cloud', async () => { + const user = await RESTController.request( 'POST', '/classes/_User', { username: 'hello', password: 'world' }, { installationId: 'my-installation' } - ) - .then(user => { - expect(user.sessionToken).not.toBeUndefined(); - const query = new Parse.Query('_Session'); - return query.find({ useMasterKey: true }); - }) - .then( - sessions => { - expect(sessions.length).toBe(1); - expect(sessions[0].get('installationId')).toBe('my-installation'); - done(); - }, - err => { - jfail(err); - done(); - } - ); + ); + expect(user.sessionToken).not.toBeUndefined(); + const query = new Parse.Query('_Session'); + const sessions = await query.find({ useMasterKey: true }); + expect(sessions.length).toBe(1); + expect(sessions[0].get('installationId')).toBe('my-installation'); }); it('ensures logIn is saved with installationId', async () => { diff --git a/spec/batch.spec.js b/spec/batch.spec.js index 98050254ba..b9e079cafe 100644 --- a/spec/batch.spec.js +++ b/spec/batch.spec.js @@ -89,10 +89,32 @@ describe('batch', () => { expect(internalURL).toEqual('/classes/Object'); }); - it('should handle a batch request without transaction', async done => { + it('should return the proper url with no url provided', () => { + const originalURL = '/parse/batch'; + const internalURL = batch.makeBatchRoutingPathFunction( + originalURL, + undefined, + publicServerURL + )('/parse/classes/Object'); + + expect(internalURL).toEqual('/classes/Object'); + }); + + it('should return the proper url with no public url provided', () => { + const originalURL = '/parse/batch'; + const internalURL = batch.makeBatchRoutingPathFunction( + originalURL, + serverURLNaked, + undefined + )('/parse/classes/Object'); + + expect(internalURL).toEqual('/classes/Object'); + }); + + it('should handle a batch request without transaction', async () => { spyOn(databaseAdapter, 'createObject').and.callThrough(); - request({ + const response = await request({ method: 'POST', headers: headers, url: 'http://localhost:8378/1/batch', @@ -110,28 +132,25 @@ describe('batch', () => { }, ], }), - }).then(response => { - expect(response.data.length).toEqual(2); - expect(response.data[0].success.objectId).toBeDefined(); - expect(response.data[0].success.createdAt).toBeDefined(); - expect(response.data[1].success.objectId).toBeDefined(); - expect(response.data[1].success.createdAt).toBeDefined(); - const query = new Parse.Query('MyObject'); - query.find().then(results => { - expect(databaseAdapter.createObject.calls.count()).toBe(2); - expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null); - expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null); - expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']); - done(); - }); }); + + expect(response.data.length).toEqual(2); + expect(response.data[0].success.objectId).toBeDefined(); + expect(response.data[0].success.createdAt).toBeDefined(); + expect(response.data[1].success.objectId).toBeDefined(); + expect(response.data[1].success.createdAt).toBeDefined(); + const query = new Parse.Query('MyObject'); + const results = await query.find(); + expect(databaseAdapter.createObject.calls.count()).toBe(2); + expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null); + expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null); + expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']); }); - it('should handle a batch request with transaction = false', async done => { - await reconfigureServer(); + it('should handle a batch request with transaction = false', async () => { spyOn(databaseAdapter, 'createObject').and.callThrough(); - request({ + const response = await request({ method: 'POST', headers: headers, url: 'http://localhost:8378/1/batch', @@ -150,21 +169,18 @@ describe('batch', () => { ], transaction: false, }), - }).then(response => { - expect(response.data.length).toEqual(2); - expect(response.data[0].success.objectId).toBeDefined(); - expect(response.data[0].success.createdAt).toBeDefined(); - expect(response.data[1].success.objectId).toBeDefined(); - expect(response.data[1].success.createdAt).toBeDefined(); - const query = new Parse.Query('MyObject'); - query.find().then(results => { - expect(databaseAdapter.createObject.calls.count()).toBe(2); - expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null); - expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null); - expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']); - done(); - }); }); + expect(response.data.length).toEqual(2); + expect(response.data[0].success.objectId).toBeDefined(); + expect(response.data[0].success.createdAt).toBeDefined(); + expect(response.data[1].success.objectId).toBeDefined(); + expect(response.data[1].success.createdAt).toBeDefined(); + const query = new Parse.Query('MyObject'); + const results = await query.find(); + expect(databaseAdapter.createObject.calls.count()).toBe(2); + expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null); + expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null); + expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']); }); if ( @@ -191,58 +207,48 @@ describe('batch', () => { } }); - it('should handle a batch request with transaction = true', async done => { - await reconfigureServer(); + it('should handle a batch request with transaction = true', async () => { const myObject = new Parse.Object('MyObject'); // This is important because transaction only works on pre-existing collections - myObject - .save() - .then(() => { - return myObject.destroy(); - }) - .then(() => { - spyOn(databaseAdapter, 'createObject').and.callThrough(); - - request({ - method: 'POST', - headers: headers, - url: 'http://localhost:8378/1/batch', - body: JSON.stringify({ - requests: [ - { - method: 'POST', - path: '/1/classes/MyObject', - body: { key: 'value1' }, - }, - { - method: 'POST', - path: '/1/classes/MyObject', - body: { key: 'value2' }, - }, - ], - transaction: true, - }), - }).then(response => { - expect(response.data.length).toEqual(2); - expect(response.data[0].success.objectId).toBeDefined(); - expect(response.data[0].success.createdAt).toBeDefined(); - expect(response.data[1].success.objectId).toBeDefined(); - expect(response.data[1].success.createdAt).toBeDefined(); - const query = new Parse.Query('MyObject'); - query.find().then(results => { - expect(databaseAdapter.createObject.calls.count() % 2).toBe(0); - for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) { - expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe( - databaseAdapter.createObject.calls.argsFor(i + 1)[3] - ); - } - expect(results.map(result => result.get('key')).sort()).toEqual([ - 'value1', - 'value2', - ]); - done(); - }); - }); - }); + await myObject.save(); + await myObject.destroy(); + spyOn(databaseAdapter, 'createObject').and.callThrough(); + const response = await request({ + method: 'POST', + headers: headers, + url: 'http://localhost:8378/1/batch', + body: JSON.stringify({ + requests: [ + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value2' }, + }, + ], + transaction: true, + }), + }); + expect(response.data.length).toEqual(2); + expect(response.data[0].success.objectId).toBeDefined(); + expect(response.data[0].success.createdAt).toBeDefined(); + expect(response.data[1].success.objectId).toBeDefined(); + expect(response.data[1].success.createdAt).toBeDefined(); + const query = new Parse.Query('MyObject'); + const results = await query.find(); + expect(databaseAdapter.createObject.calls.count() % 2).toBe(0); + for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) { + expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe( + databaseAdapter.createObject.calls.argsFor(i + 1)[3] + ); + } + expect(results.map(result => result.get('key')).sort()).toEqual([ + 'value1', + 'value2', + ]); }); it('should not save anything when one operation fails in a transaction', async () => { @@ -350,6 +356,7 @@ describe('batch', () => { transaction: true, }), }); + fail(); } catch (error) { expect(error).toBeDefined(); const query = new Parse.Query('MyObject'); From a5ffb9502232c03fe87692724e9d6449ac66ad00 Mon Sep 17 00:00:00 2001 From: Corey Date: Thu, 6 Jan 2022 09:26:00 -0500 Subject: [PATCH 46/83] refactor: remove deprecated `url.parse()` method (#7751) --- spec/AuthenticationAdapters.spec.js | 18 +++++++++++++++ spec/batch.spec.js | 22 +++++++++++++++++++ src/Adapters/Auth/gcenter.js | 19 +++++++++------- src/Adapters/Auth/oauth2.js | 3 +-- .../Storage/Postgres/PostgresConfigParser.js | 10 ++++----- src/Controllers/LoggerController.js | 12 +++++----- src/Controllers/index.js | 3 +-- src/ParseServerRESTController.js | 7 +++--- src/batch.js | 16 +++++++------- 9 files changed, 74 insertions(+), 36 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index d32eba0423..89eeb51231 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -1707,6 +1707,24 @@ describe('Apple Game Center Auth adapter', () => { expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: invalid.com'); } }); + + it('validateAuthData invalid public key http url', async () => { + const authData = { + id: 'G:1965586982', + publicKeyUrl: 'http://static.gc.apple.com/public-key/gc-prod-4.cer', + timestamp: 1565257031287, + signature: '1234', + salt: 'DzqqrQ==', + bundleId: 'cloud.xtralife.gamecenterauth', + }; + + try { + await gcenter.validateAuthData(authData); + fail(); + } catch (e) { + expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: http://static.gc.apple.com/public-key/gc-prod-4.cer'); + } + }); }); describe('phant auth adapter', () => { diff --git a/spec/batch.spec.js b/spec/batch.spec.js index b9e079cafe..f91f91a0b5 100644 --- a/spec/batch.spec.js +++ b/spec/batch.spec.js @@ -111,6 +111,28 @@ describe('batch', () => { expect(internalURL).toEqual('/classes/Object'); }); + it('should return the proper url with bad url provided', () => { + const originalURL = '/parse/batch'; + const internalURL = batch.makeBatchRoutingPathFunction( + originalURL, + 'badurl.com', + publicServerURL + )('/parse/classes/Object'); + + expect(internalURL).toEqual('/classes/Object'); + }); + + it('should return the proper url with bad public url provided', () => { + const originalURL = '/parse/batch'; + const internalURL = batch.makeBatchRoutingPathFunction( + originalURL, + serverURLNaked, + 'badurl.com' + )('/parse/classes/Object'); + + expect(internalURL).toEqual('/classes/Object'); + }); + it('should handle a batch request without transaction', async () => { spyOn(databaseAdapter, 'createObject').and.callThrough(); diff --git a/src/Adapters/Auth/gcenter.js b/src/Adapters/Auth/gcenter.js index 090b9fab02..322c2430d1 100644 --- a/src/Adapters/Auth/gcenter.js +++ b/src/Adapters/Auth/gcenter.js @@ -14,20 +14,23 @@ const authData = { const { Parse } = require('parse/node'); const crypto = require('crypto'); const https = require('https'); -const url = require('url'); const cache = {}; // (publicKey -> cert) cache function verifyPublicKeyUrl(publicKeyUrl) { - const parsedUrl = url.parse(publicKeyUrl); - if (parsedUrl.protocol !== 'https:') { + try { + const parsedUrl = new URL(publicKeyUrl); + if (parsedUrl.protocol !== 'https:') { + return false; + } + const hostnameParts = parsedUrl.hostname.split('.'); + const length = hostnameParts.length; + const domainParts = hostnameParts.slice(length - 2, length); + const domain = domainParts.join('.'); + return domain === 'apple.com'; + } catch(error) { return false; } - const hostnameParts = parsedUrl.hostname.split('.'); - const length = hostnameParts.length; - const domainParts = hostnameParts.slice(length - 2, length); - const domain = domainParts.join('.'); - return domain === 'apple.com'; } function convertX509CertToPEM(X509Cert) { diff --git a/src/Adapters/Auth/oauth2.js b/src/Adapters/Auth/oauth2.js index cefe7bdff2..ba1fe7bc4f 100644 --- a/src/Adapters/Auth/oauth2.js +++ b/src/Adapters/Auth/oauth2.js @@ -54,7 +54,6 @@ */ const Parse = require('parse/node').Parse; -const url = require('url'); const querystring = require('querystring'); const httpsRequest = require('./httpsRequest'); @@ -112,7 +111,7 @@ function requestTokenInfo(options, access_token) { if (!options || !options.tokenIntrospectionEndpointUrl) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, MISSING_URL); } - const parsedUrl = url.parse(options.tokenIntrospectionEndpointUrl); + const parsedUrl = new URL(options.tokenIntrospectionEndpointUrl); const postData = querystring.stringify({ token: access_token, }); diff --git a/src/Adapters/Storage/Postgres/PostgresConfigParser.js b/src/Adapters/Storage/Postgres/PostgresConfigParser.js index 170e76282a..d86778cf20 100644 --- a/src/Adapters/Storage/Postgres/PostgresConfigParser.js +++ b/src/Adapters/Storage/Postgres/PostgresConfigParser.js @@ -1,18 +1,16 @@ -const url = require('url'); const fs = require('fs'); function getDatabaseOptionsFromURI(uri) { const databaseOptions = {}; - const parsedURI = url.parse(uri); - const queryParams = parseQueryParams(parsedURI.query); - const authParts = parsedURI.auth ? parsedURI.auth.split(':') : []; + const parsedURI = new URL(uri); + const queryParams = parseQueryParams(parsedURI.searchParams.toString()); databaseOptions.host = parsedURI.hostname || 'localhost'; databaseOptions.port = parsedURI.port ? parseInt(parsedURI.port) : 5432; databaseOptions.database = parsedURI.pathname ? parsedURI.pathname.substr(1) : undefined; - databaseOptions.user = authParts.length > 0 ? authParts[0] : ''; - databaseOptions.password = authParts.length > 1 ? authParts[1] : ''; + databaseOptions.user = parsedURI.username; + databaseOptions.password = parsedURI.password; if (queryParams.ssl && queryParams.ssl.toLowerCase() === 'true') { databaseOptions.ssl = true; diff --git a/src/Controllers/LoggerController.js b/src/Controllers/LoggerController.js index 04d3a6d784..8ee492cf4b 100644 --- a/src/Controllers/LoggerController.js +++ b/src/Controllers/LoggerController.js @@ -1,7 +1,6 @@ import { Parse } from 'parse/node'; import AdaptableController from './AdaptableController'; import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter'; -import url from 'url'; const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000; const LOG_STRING_TRUNCATE_LENGTH = 1000; @@ -38,15 +37,16 @@ export class LoggerController extends AdaptableController { }); } - maskSensitiveUrl(urlString) { - const urlObj = url.parse(urlString, true); - const query = urlObj.query; + maskSensitiveUrl(path) { + const urlString = 'http://localhost' + path; // prepend dummy string to make a real URL + const urlObj = new URL(urlString); + const query = urlObj.searchParams; let sanitizedQuery = '?'; - for (const key in query) { + for (const [key, value] of query) { if (key !== 'password') { // normal value - sanitizedQuery += key + '=' + query[key] + '&'; + sanitizedQuery += key + '=' + value + '&'; } else { // password value, redact it sanitizedQuery += key + '=' + '********' + '&'; diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 71ab5ef486..152de684fe 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -2,7 +2,6 @@ import authDataManager from '../Adapters/Auth'; import { ParseServerOptions } from '../Options'; import { loadAdapter } from '../Adapters/AdapterLoader'; import defaults from '../defaults'; -import url from 'url'; // Controllers import { LoggerController } from './LoggerController'; import { FilesController } from './FilesController'; @@ -220,7 +219,7 @@ export function getAuthDataManager(options: ParseServerOptions) { export function getDatabaseAdapter(databaseURI, collectionPrefix, databaseOptions) { let protocol; try { - const parsedURI = url.parse(databaseURI); + const parsedURI = new URL(databaseURI); protocol = parsedURI.protocol ? parsedURI.protocol.toLowerCase() : null; } catch (e) { /* */ diff --git a/src/ParseServerRESTController.js b/src/ParseServerRESTController.js index 9e765ff3e3..12ee0a67e5 100644 --- a/src/ParseServerRESTController.js +++ b/src/ParseServerRESTController.js @@ -1,7 +1,6 @@ const Config = require('./Config'); const Auth = require('./Auth'); const RESTController = require('parse/lib/node/RESTController'); -const URL = require('url'); const Parse = require('parse/node'); function getSessionToken(options) { @@ -38,9 +37,9 @@ function ParseServerRESTController(applicationId, router) { if (!config) { config = Config.get(applicationId); } - const serverURL = URL.parse(config.serverURL); - if (path.indexOf(serverURL.path) === 0) { - path = path.slice(serverURL.path.length, path.length); + const serverURL = new URL(config.serverURL); + if (path.indexOf(serverURL.pathname) === 0) { + path = path.slice(serverURL.pathname.length, path.length); } if (path[0] !== '/') { diff --git a/src/batch.js b/src/batch.js index 58c23ccab6..0625ef0ecc 100644 --- a/src/batch.js +++ b/src/batch.js @@ -1,5 +1,4 @@ const Parse = require('parse/node').Parse; -const url = require('url'); const path = require('path'); // These methods handle batch requests. const batchPath = '/batch'; @@ -11,11 +10,12 @@ function mountOnto(router) { }); } -function parseURL(URL) { - if (typeof URL === 'string') { - return url.parse(URL); +function parseURL(urlString) { + try { + return new URL(urlString); + } catch(error) { + return undefined; } - return undefined; } function makeBatchRoutingPathFunction(originalUrl, serverURL, publicServerURL) { @@ -33,9 +33,9 @@ function makeBatchRoutingPathFunction(originalUrl, serverURL, publicServerURL) { return path.posix.join('/', requestPath.slice(apiPrefix.length)); }; - if (serverURL && publicServerURL && serverURL.path != publicServerURL.path) { - const localPath = serverURL.path; - const publicPath = publicServerURL.path; + if (serverURL && publicServerURL && serverURL.pathname != publicServerURL.pathname) { + const localPath = serverURL.pathname; + const publicPath = publicServerURL.pathname; // Override the api prefix apiPrefix = localPath; From 5af6e5dfaa129b1a350afcba4fb381b21c4cc35d Mon Sep 17 00:00:00 2001 From: ThornWu Date: Thu, 13 Jan 2022 09:03:33 +0800 Subject: [PATCH 47/83] fix: schema cache not cleared in some cases (#7678) --- spec/schemas.spec.js | 87 ++++++++++++++++++++++++++++++++++++ src/Routers/SchemasRouter.js | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index e8dcc41e4d..9557dd7924 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -5,6 +5,7 @@ const dd = require('deep-diff'); const Config = require('../lib/Config'); const request = require('../lib/request'); const TestUtils = require('../lib/TestUtils'); +const SchemaController = require('../lib/Controllers/SchemaController').SchemaController; let config; @@ -239,6 +240,52 @@ describe('schemas', () => { }); }); + it('ensure refresh cache after creating a class', async done => { + spyOn(SchemaController.prototype, 'reloadData').and.callFake(() => Promise.resolve()); + await request({ + url: 'http://localhost:8378/1/schemas', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'A', + }, + }); + const response = await request({ + url: 'http://localhost:8378/1/schemas', + method: 'GET', + headers: masterKeyHeaders, + json: true, + }); + const expected = { + results: [ + userSchema, + roleSchema, + { + className: 'A', + fields: { + //Default fields + ACL: { type: 'ACL' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + objectId: { type: 'String' }, + }, + classLevelPermissions: defaultClassLevelPermissions, + }, + ], + }; + expect( + response.data.results + .sort((s1, s2) => s1.className.localeCompare(s2.className)) + .map(s => { + const withoutIndexes = Object.assign({}, s); + delete withoutIndexes.indexes; + return withoutIndexes; + }) + ).toEqual(expected.results.sort((s1, s2) => s1.className.localeCompare(s2.className))); + done(); + }); + it('responds with a single schema', done => { const obj = hasAllPODobject(); obj.save().then(() => { @@ -1507,6 +1554,46 @@ describe('schemas', () => { }); }); + it('ensure refresh cache after deleting a class', async done => { + config = Config.get('test'); + spyOn(config.schemaCache, 'del').and.callFake(() => {}); + spyOn(SchemaController.prototype, 'reloadData').and.callFake(() => Promise.resolve()); + await request({ + url: 'http://localhost:8378/1/schemas', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'A', + }, + }); + await request({ + method: 'DELETE', + url: 'http://localhost:8378/1/schemas/A', + headers: masterKeyHeaders, + json: true, + }); + const response = await request({ + url: 'http://localhost:8378/1/schemas', + method: 'GET', + headers: masterKeyHeaders, + json: true, + }); + const expected = { + results: [userSchema, roleSchema], + }; + expect( + response.data.results + .sort((s1, s2) => s1.className.localeCompare(s2.className)) + .map(s => { + const withoutIndexes = Object.assign({}, s); + delete withoutIndexes.indexes; + return withoutIndexes; + }) + ).toEqual(expected.results.sort((s1, s2) => s1.className.localeCompare(s2.className))); + done(); + }); + it('deletes collections including join tables', done => { const obj = new Parse.Object('MyClass'); obj.set('data', 'data'); diff --git a/src/Routers/SchemasRouter.js b/src/Routers/SchemasRouter.js index 54f73ceacc..1b72b93a68 100644 --- a/src/Routers/SchemasRouter.js +++ b/src/Routers/SchemasRouter.js @@ -16,7 +16,7 @@ function classNameMismatchResponse(bodyClass, pathClass) { function getAllSchemas(req) { return req.config.database .loadSchema({ clearCache: true }) - .then(schemaController => schemaController.getAllClasses(true)) + .then(schemaController => schemaController.getAllClasses({ clearCache: true })) .then(schemas => ({ response: { results: schemas } })); } From 98abd7112c633f38ac108c64dc2f1d0ba89f5237 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 13 Jan 2022 01:04:40 +0000 Subject: [PATCH 48/83] chore(release): 5.0.0-alpha.17 [skip ci] # [5.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.16...5.0.0-alpha.17) (2022-01-13) ### Bug Fixes * schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index a3b6cd12d5..2f2681be08 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.16...5.0.0-alpha.17) (2022-01-13) + + +### Bug Fixes + +* schema cache not cleared in some cases ([#7678](https://github.com/parse-community/parse-server/issues/7678)) ([5af6e5d](https://github.com/parse-community/parse-server/commit/5af6e5dfaa129b1a350afcba4fb381b21c4cc35d)) + # [5.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.15...5.0.0-alpha.16) (2022-01-02) diff --git a/package-lock.json b/package-lock.json index 2bfd0ece4f..66dd1eae33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.16", + "version": "5.0.0-alpha.17", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 514f0be0eb..fdf01da53b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.16", + "version": "5.0.0-alpha.17", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Thu, 13 Jan 2022 02:05:15 +0000 Subject: [PATCH 49/83] fix: security upgrade follow-redirects from 1.14.6 to 1.14.7 (#7769) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66dd1eae33..2977b1ce49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7041,9 +7041,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.14.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", - "integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==" + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", + "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index fdf01da53b..888295963c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "cors": "2.8.5", "deepcopy": "2.1.0", "express": "4.17.1", - "follow-redirects": "1.14.6", + "follow-redirects": "1.14.7", "graphql": "15.7.1", "graphql-list-fields": "2.0.2", "graphql-relay": "0.7.0", From c720fbba5a70d0497087851192d37502055e9c46 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 13 Jan 2022 02:14:07 +0000 Subject: [PATCH 50/83] chore(release): 5.0.0-alpha.18 [skip ci] # [5.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.17...5.0.0-alpha.18) (2022-01-13) ### Bug Fixes * security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 2f2681be08..ea3b0f5d50 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.17...5.0.0-alpha.18) (2022-01-13) + + +### Bug Fixes + +* security upgrade follow-redirects from 1.14.6 to 1.14.7 ([#7769](https://github.com/parse-community/parse-server/issues/7769)) ([8f5a861](https://github.com/parse-community/parse-server/commit/8f5a8618cfa7ed9a2a239a095abffa8f3fd8d31a)) + # [5.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.16...5.0.0-alpha.17) (2022-01-13) diff --git a/package-lock.json b/package-lock.json index 2977b1ce49..08e7e9316b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.17", + "version": "5.0.0-alpha.18", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 888295963c..2807e5c934 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.17", + "version": "5.0.0-alpha.18", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 826aa79b9fb1c7c65ae8e72726c97a9d7acb40c4 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Fri, 14 Jan 2022 13:22:30 +0000 Subject: [PATCH 51/83] refactor: upgrade express from 4.17.1 to 4.17.2 (#7776) --- package-lock.json | 146 +++++++++++++++------------------------------- package.json | 2 +- 2 files changed, 49 insertions(+), 99 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08e7e9316b..d537918da6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4601,6 +4601,7 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, "requires": { "safe-buffer": "5.1.2" }, @@ -4608,7 +4609,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true } } }, @@ -4737,9 +4739,9 @@ } }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" }, "cookie-signature": { "version": "1.0.6", @@ -6357,16 +6359,16 @@ } }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", "requires": { "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -6380,41 +6382,27 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" } }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6423,48 +6411,10 @@ "ms": "2.0.0" } }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" } } }, @@ -15039,9 +14989,9 @@ "dev": true }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -15050,9 +15000,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -15074,15 +15024,15 @@ } }, "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", "inherits": "2.0.4", - "setprototypeof": "1.1.1", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, "mime": { @@ -15091,26 +15041,26 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" } } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" } }, "set-blocking": { diff --git a/package.json b/package.json index 2807e5c934..8fc64dc6c2 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "commander": "5.1.0", "cors": "2.8.5", "deepcopy": "2.1.0", - "express": "4.17.1", + "express": "4.17.2", "follow-redirects": "1.14.7", "graphql": "15.7.1", "graphql-list-fields": "2.0.2", From f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Jan 2022 13:54:53 +0100 Subject: [PATCH 52/83] fix: bump nanoid from 3.1.25 to 3.2.0 (#7781) --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d537918da6..060a5f44f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10628,9 +10628,9 @@ "optional": true }, "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", "dev": true }, "nanomatch": { From f105d7aef1f964e95d7e5e3fa0df1c5a24bd9750 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 22 Jan 2022 12:59:57 +0000 Subject: [PATCH 53/83] chore(release): 5.0.0-alpha.19 [skip ci] # [5.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.18...5.0.0-alpha.19) (2022-01-22) ### Bug Fixes * bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index ea3b0f5d50..de391202db 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.18...5.0.0-alpha.19) (2022-01-22) + + +### Bug Fixes + +* bump nanoid from 3.1.25 to 3.2.0 ([#7781](https://github.com/parse-community/parse-server/issues/7781)) ([f5f63bf](https://github.com/parse-community/parse-server/commit/f5f63bfc64d3481ed944ceb5e9f50b33dccd1ce9)) + # [5.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.17...5.0.0-alpha.18) (2022-01-13) diff --git a/package-lock.json b/package-lock.json index 060a5f44f6..3f2e035cd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.18", + "version": "5.0.0-alpha.19", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8fc64dc6c2..9394d06cd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.18", + "version": "5.0.0-alpha.19", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 90823514113a1a085ebc818f7109b3fd7591346f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Jan 2022 14:31:45 +0100 Subject: [PATCH 54/83] fix: bump node-fetch from 2.6.1 to 3.1.1 (#7782) --- package-lock.json | 103 +++++++++++++++++++++++++++++++- package.json | 2 +- spec/ParseGraphQLServer.spec.js | 20 ++++--- 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f2e035cd0..e8622c960e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1782,6 +1782,15 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } } } }, @@ -3153,6 +3162,16 @@ "requires": { "node-fetch": "^2.6.1", "util.promisify": "^1.0.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } } }, "apollo-server-errors": { @@ -4820,6 +4839,13 @@ "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", "requires": { "node-fetch": "2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + } } }, "cross-spawn": { @@ -4885,6 +4911,12 @@ "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", + "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "dev": true + }, "dataloader": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz", @@ -6683,6 +6715,16 @@ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" }, + "fetch-blob": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz", + "integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==", + "dev": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "fetch-node-website": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/fetch-node-website/-/fetch-node-website-5.0.3.tgz", @@ -7036,6 +7078,15 @@ "mime-types": "^2.1.12" } }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -10426,6 +10477,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } } } }, @@ -10696,6 +10756,12 @@ "tslib": "^2.0.3" } }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true + }, "node-emoji": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", @@ -10706,9 +10772,15 @@ } }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.1.1.tgz", + "integrity": "sha512-SMk+vKgU77PYotRdWzqZGTZeuFKlsJ0hu4KPviQKkfY+N3vn2MIzr0rvpnYpR8MtB3IEuhlEcuOLbGvLRlA+yg==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.3", + "formdata-polyfill": "^4.0.10" + } }, "node-forge": { "version": "0.10.0", @@ -16114,6 +16186,11 @@ } } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "traverse": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", @@ -16556,6 +16633,26 @@ "defaults": "^1.0.3" } }, + "web-streams-polyfill": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz", + "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 9394d06cd8..2ad6ec3478 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "mock-mail-adapter": "file:spec/dependencies/mock-mail-adapter", "mongodb-runner": "4.8.1", "mongodb-version-list": "1.0.0", - "node-fetch": "2.6.1", + "node-fetch": "3.1.1", "nyc": "15.1.0", "prettier": "2.0.5", "semantic-release": "17.4.6", diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index d204886fe5..6541092b97 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1,7 +1,7 @@ const http = require('http'); const express = require('express'); const req = require('../lib/request'); -const fetch = require('node-fetch'); +const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args)); const FormData = require('form-data'); const ws = require('ws'); require('./helper'); @@ -2600,18 +2600,22 @@ describe('ParseGraphQLServer', () => { // "SecondaryObject:bBRgmzIRRM" < "SecondaryObject:nTMcuVbATY" true // base64("SecondaryObject:bBRgmzIRRM"") < base64(""SecondaryObject:nTMcuVbATY"") false // "U2Vjb25kYXJ5T2JqZWN0OmJCUmdteklSUk0=" < "U2Vjb25kYXJ5T2JqZWN0Om5UTWN1VmJBVFk=" false - const originalIds = [getSecondaryObjectsResult.data.secondaryObject2.objectId, - getSecondaryObjectsResult.data.secondaryObject4.objectId]; + const originalIds = [ + getSecondaryObjectsResult.data.secondaryObject2.objectId, + getSecondaryObjectsResult.data.secondaryObject4.objectId, + ]; expect( findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.objectId - ).not.toBe( - findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.objectId - ); + ).not.toBe(findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.objectId); expect( - originalIds.includes(findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.objectId) + originalIds.includes( + findSecondaryObjectsResult.data.secondaryObjects.edges[0].node.objectId + ) ).toBeTrue(); expect( - originalIds.includes(findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.objectId) + originalIds.includes( + findSecondaryObjectsResult.data.secondaryObjects.edges[1].node.objectId + ) ).toBeTrue(); const createPrimaryObjectResult = await apolloClient.mutate({ From 350b59ac5f936329e494bb2caab63fbdbba7d90f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 22 Jan 2022 13:32:51 +0000 Subject: [PATCH 55/83] chore(release): 5.0.0-alpha.20 [skip ci] # [5.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.19...5.0.0-alpha.20) (2022-01-22) ### Bug Fixes * bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index de391202db..7433ea0d23 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.19...5.0.0-alpha.20) (2022-01-22) + + +### Bug Fixes + +* bump node-fetch from 2.6.1 to 3.1.1 ([#7782](https://github.com/parse-community/parse-server/issues/7782)) ([9082351](https://github.com/parse-community/parse-server/commit/90823514113a1a085ebc818f7109b3fd7591346f)) + # [5.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.18...5.0.0-alpha.19) (2022-01-22) diff --git a/package-lock.json b/package-lock.json index e8622c960e..a13b5cbaa0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.19", + "version": "5.0.0-alpha.20", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2ad6ec3478..6203c6f2df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.19", + "version": "5.0.0-alpha.20", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 433e82f1df627f3905ba69be99da6402710b5366 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Tue, 25 Jan 2022 00:42:55 +0000 Subject: [PATCH 56/83] refactor: upgrade parse from 3.4.0 to 3.4.1 (#7783) --- package-lock.json | 21 +++++++++++++++++---- package.json | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a13b5cbaa0..9641878cdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13509,14 +13509,14 @@ } }, "parse": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.0.tgz", - "integrity": "sha512-FMZLxPW6PvrBgxkXc9AmnYsFKvPwiS4G2n9OI4mdfiSoNzIVLc+bXzlUdJ+I7hiqHsBTP0BrdQczw2/cnVkJ6w==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.1.tgz", + "integrity": "sha512-XTMaHfcOwAOiWLraNtPbCzR8o94ZWjOfaZDMM2jZ1ZDB5twtK1B82lPa+N197efZhcQ+QFbW/eDJsBybD48aSQ==", "requires": { "@babel/runtime": "7.15.4", "@babel/runtime-corejs3": "7.14.7", "crypto-js": "4.1.1", - "idb-keyval": "5.0.6", + "idb-keyval": "6.0.3", "react-native-crypto-js": "1.0.0", "uuid": "3.4.0", "ws": "7.5.1", @@ -13540,6 +13540,14 @@ "regenerator-runtime": "^0.13.4" } }, + "idb-keyval": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.0.3.tgz", + "integrity": "sha512-yh8V7CnE6EQMu9YDwQXhRxwZh4nv+8xm/HV4ZqK4IiYFJBWYGjJuykADJbSP+F/GDXUBwCSSNn/14IpGL81TuA==", + "requires": { + "safari-14-idb-fix": "^3.0.0" + } + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -14680,6 +14688,11 @@ } } }, + "safari-14-idb-fix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz", + "integrity": "sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", diff --git a/package.json b/package.json index 6203c6f2df..58bde7f059 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "mime": "3.0.0", "mongodb": "3.6.11", "mustache": "4.2.0", - "parse": "3.4.0", + "parse": "3.4.1", "pg-monitor": "1.4.1", "pg-promise": "10.11.1", "pluralize": "8.0.0", From 315290d16110110938f80a6b779cc2d1db58c552 Mon Sep 17 00:00:00 2001 From: yog27ray Date: Tue, 25 Jan 2022 17:10:22 +0530 Subject: [PATCH 57/83] feat: add Cloud Code context to `ParseObject.fetch` (#7779) --- spec/CloudCode.spec.js | 15 +++++++++++++++ src/Routers/ClassesRouter.js | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index c185eac53e..4b8df9f9c9 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3224,6 +3224,21 @@ describe('afterLogin hook', () => { const query = new Parse.Query(TestObject); await query.find({ context: { a: 'a' } }); }); + + it('beforeFind and afterFind should have access to context while making fetch call', async () => { + Parse.Cloud.beforeFind('TestObject', req => { + expect(req.context.a).toEqual('a'); + expect(req.context.b).toBeUndefined(); + req.context.b = 'b'; + }); + Parse.Cloud.afterFind('TestObject', req => { + expect(req.context.a).toEqual('a'); + expect(req.context.b).toEqual('b'); + }); + const obj = new TestObject(); + await obj.save(); + await obj.fetch({ context: { a: 'a' } }); + }); }); describe('saveFile hooks', () => { diff --git a/src/Routers/ClassesRouter.js b/src/Routers/ClassesRouter.js index 6788d93e5f..7f3e0a84f3 100644 --- a/src/Routers/ClassesRouter.js +++ b/src/Routers/ClassesRouter.js @@ -83,7 +83,8 @@ export class ClassesRouter extends PromiseRouter { this.className(req), req.params.objectId, options, - req.info.clientSDK + req.info.clientSDK, + req.info.context ) .then(response => { if (!response.results || response.results.length == 0) { From 1299f0697c48b57aa2294b936ae53ff129f8c844 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 25 Jan 2022 11:41:15 +0000 Subject: [PATCH 58/83] chore(release): 5.0.0-alpha.21 [skip ci] # [5.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.20...5.0.0-alpha.21) (2022-01-25) ### Features * add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 7433ea0d23..a78e3f0637 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.20...5.0.0-alpha.21) (2022-01-25) + + +### Features + +* add Cloud Code context to `ParseObject.fetch` ([#7779](https://github.com/parse-community/parse-server/issues/7779)) ([315290d](https://github.com/parse-community/parse-server/commit/315290d16110110938f80a6b779cc2d1db58c552)) + # [5.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.19...5.0.0-alpha.20) (2022-01-22) diff --git a/package-lock.json b/package-lock.json index 9641878cdb..17701ad364 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.20", + "version": "5.0.0-alpha.21", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 58bde7f059..5067906b30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.20", + "version": "5.0.0-alpha.21", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From f88aa2a62a533e5344d1c13dd38c5a0b283a480a Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Sun, 6 Feb 2022 18:30:36 +0100 Subject: [PATCH 59/83] feat: upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support (#7794) BREAKING CHANGE: The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. --- package-lock.json | 135 ++++++- package.json | 11 +- spec/AudienceRouter.spec.js | 29 +- spec/FilesController.spec.js | 43 +- spec/GridFSBucketStorageAdapter.spec.js | 19 +- spec/GridStoreAdapter.spec.js | 111 ------ spec/MongoStorageAdapter.spec.js | 55 ++- spec/ParseGraphQLServer.spec.js | 93 ++--- spec/ReadPreferenceOption.spec.js | 372 ++++++++---------- src/Adapters/Files/GridFSBucketAdapter.js | 2 +- src/Adapters/Files/GridStoreAdapter.js | 185 +-------- .../Storage/Mongo/MongoSchemaCollection.js | 2 +- .../Storage/Mongo/MongoStorageAdapter.js | 5 +- 13 files changed, 393 insertions(+), 669 deletions(-) delete mode 100644 spec/GridStoreAdapter.spec.js diff --git a/package-lock.json b/package-lock.json index 17701ad364..045195ff54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,6 +2650,20 @@ "@types/node": "*" } }, + "@types/webidl-conversions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", + "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==" + }, + "@types/whatwg-url": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", + "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -3603,8 +3617,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bcrypt-nodejs": { "version": "0.0.3", @@ -3652,6 +3665,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "dev": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -3788,13 +3802,13 @@ "bson": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "dev": true }, "buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -7940,8 +7954,7 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "4.0.6", @@ -8153,6 +8166,11 @@ "loose-envify": "^1.0.0" } }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -10388,16 +10406,63 @@ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "mongodb": { - "version": "3.6.11", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.11.tgz", - "integrity": "sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw==", - "requires": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.0.3", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz", + "integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==", + "requires": { + "bson": "^4.6.1", + "denque": "^2.0.1", + "mongodb-connection-string-url": "^2.4.1", + "saslprep": "^1.0.3", + "socks": "^2.6.1" + }, + "dependencies": { + "bson": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.1.tgz", + "integrity": "sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw==", + "requires": { + "buffer": "^5.6.0" + } + }, + "denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" + } + } + }, + "mongodb-connection-string-url": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.4.1.tgz", + "integrity": "sha512-d5Kd2bVsKcSA7YI/yo57fSTtMwRQdFkvc5IZwod1RRxJtECeWPPSo7zqcUGJELifRA//Igs4spVtYAmvFCatug==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + }, + "dependencies": { + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + } } }, "mongodb-core": { @@ -10520,6 +10585,20 @@ "ms": "2.1.2" } }, + "mongodb": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", + "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "dev": true, + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -13233,9 +13312,10 @@ } }, "optional-require": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.7.tgz", - "integrity": "sha512-cIeRZocXsZnZYn+SevbtSqNlLbeoS4mLzuNn4fvXRMDRNhTGg0sxuKXl0FnZCtnew85LorNxIbZp5OeliILhMw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "dev": true, "requires": { "require-at": "^1.0.6" } @@ -14518,7 +14598,8 @@ "require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", - "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==" + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "dev": true }, "require-directory": { "version": "2.1.1", @@ -15277,6 +15358,11 @@ } } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -15411,6 +15497,15 @@ } } }, + "socks": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", + "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + } + }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", diff --git a/package.json b/package.json index 5067906b30..8129cb2f19 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "lodash": "4.17.21", "lru-cache": "5.1.1", "mime": "3.0.0", - "mongodb": "3.6.11", + "mongodb": "4.3.1", "mustache": "4.2.0", "parse": "3.4.1", "pg-monitor": "1.4.1", @@ -118,12 +118,13 @@ "test:mongodb:4.0.27": "npm run test:mongodb --dbversion=4.0.27", "test:mongodb:4.2.17": "npm run test:mongodb --dbversion=4.2.17", "test:mongodb:4.4.10": "npm run test:mongodb --dbversion=4.4.10", + "test:mongodb:5.0.5": "npm run test:mongodb --dbversion=5.0.5", "posttest:mongodb": "mongodb-runner stop", - "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.4.10} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start", - "testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.4.10} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 jasmine", + "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start", + "testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 jasmine", "test": "npm run testonly", - "posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.4.10} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner stop", - "coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.4.10} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 nyc jasmine", + "posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner stop", + "coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.0.5} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 nyc jasmine", "start": "node ./bin/parse-server", "prettier": "prettier --write {src,spec}/{**/*,*}.js", "prepare": "npm run build", diff --git a/spec/AudienceRouter.spec.js b/spec/AudienceRouter.spec.js index 208e7834b6..9f0f77896a 100644 --- a/spec/AudienceRouter.spec.js +++ b/spec/AudienceRouter.spec.js @@ -326,22 +326,24 @@ describe('AudiencesRouter', () => { { name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' }) }, { useMasterKey: true } ).then(audience => { - database.collection('test__Audience').updateOne( - { _id: audience.objectId }, - { - $set: { - times_used: 1, - _last_used: now, - }, - }, - {}, - error => { - expect(error).toEqual(null); + database + .collection('test__Audience') + .updateOne( + { _id: audience.objectId }, + { + $set: { + times_used: 1, + _last_used: now, + }, + } + ) + .then(result => { + expect(result).toBeTruthy(); database .collection('test__Audience') .find({ _id: audience.objectId }) .toArray((error, rows) => { - expect(error).toEqual(null); + expect(error).toEqual(undefined); expect(rows[0]['times_used']).toEqual(1); expect(rows[0]['_last_used']).toEqual(now); Parse._request( @@ -361,8 +363,7 @@ describe('AudiencesRouter', () => { done.fail(error); }); }); - } - ); + }); }); }); diff --git a/spec/FilesController.spec.js b/spec/FilesController.spec.js index 996e4c3961..9ea66da6ea 100644 --- a/spec/FilesController.spec.js +++ b/spec/FilesController.spec.js @@ -3,7 +3,6 @@ const WinstonLoggerAdapter = require('../lib/Adapters/Logger/WinstonLoggerAdapte .WinstonLoggerAdapter; const GridFSBucketAdapter = require('../lib/Adapters/Files/GridFSBucketAdapter') .GridFSBucketAdapter; -const GridStoreAdapter = require('../lib/Adapters/Files/GridStoreAdapter').GridStoreAdapter; const Config = require('../lib/Config'); const FilesController = require('../lib/Controllers/FilesController').default; const databaseURI = 'mongodb://localhost:27017/parse'; @@ -24,8 +23,8 @@ const mockAdapter = { describe('FilesController', () => { it('should properly expand objects', done => { const config = Config.get(Parse.applicationId); - const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); - const filesController = new FilesController(gridStoreAdapter); + const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); + const filesController = new FilesController(gridFSAdapter); const result = filesController.expandFilesInObject(config, function () {}); expect(result).toBeUndefined(); @@ -88,19 +87,19 @@ describe('FilesController', () => { it('should add a unique hash to the file name when the preserveFileName option is false', done => { const config = Config.get(Parse.applicationId); - const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); - spyOn(gridStoreAdapter, 'createFile'); - gridStoreAdapter.createFile.and.returnValue(Promise.resolve()); + const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); + spyOn(gridFSAdapter, 'createFile'); + gridFSAdapter.createFile.and.returnValue(Promise.resolve()); const fileName = 'randomFileName.pdf'; const regexEscapedFileName = fileName.replace(/\./g, '\\$&'); - const filesController = new FilesController(gridStoreAdapter, null, { + const filesController = new FilesController(gridFSAdapter, null, { preserveFileName: false, }); filesController.createFile(config, fileName); - expect(gridStoreAdapter.createFile).toHaveBeenCalledTimes(1); - expect(gridStoreAdapter.createFile.calls.mostRecent().args[0]).toMatch( + expect(gridFSAdapter.createFile).toHaveBeenCalledTimes(1); + expect(gridFSAdapter.createFile.calls.mostRecent().args[0]).toMatch( `^.{32}_${regexEscapedFileName}$` ); @@ -109,42 +108,42 @@ describe('FilesController', () => { it('should not add a unique hash to the file name when the preserveFileName option is true', done => { const config = Config.get(Parse.applicationId); - const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); - spyOn(gridStoreAdapter, 'createFile'); - gridStoreAdapter.createFile.and.returnValue(Promise.resolve()); + const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); + spyOn(gridFSAdapter, 'createFile'); + gridFSAdapter.createFile.and.returnValue(Promise.resolve()); const fileName = 'randomFileName.pdf'; - const filesController = new FilesController(gridStoreAdapter, null, { + const filesController = new FilesController(gridFSAdapter, null, { preserveFileName: true, }); filesController.createFile(config, fileName); - expect(gridStoreAdapter.createFile).toHaveBeenCalledTimes(1); - expect(gridStoreAdapter.createFile.calls.mostRecent().args[0]).toEqual(fileName); + expect(gridFSAdapter.createFile).toHaveBeenCalledTimes(1); + expect(gridFSAdapter.createFile.calls.mostRecent().args[0]).toEqual(fileName); done(); }); it('should handle adapter without getMetadata', async () => { - const gridStoreAdapter = new GridFSBucketAdapter(databaseURI); - gridStoreAdapter.getMetadata = null; - const filesController = new FilesController(gridStoreAdapter); + const gridFSAdapter = new GridFSBucketAdapter(databaseURI); + gridFSAdapter.getMetadata = null; + const filesController = new FilesController(gridFSAdapter); const result = await filesController.getMetadata(); expect(result).toEqual({}); }); it('should reject slashes in file names', done => { - const gridStoreAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); + const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); const fileName = 'foo/randomFileName.pdf'; - expect(gridStoreAdapter.validateFilename(fileName)).not.toBe(null); + expect(gridFSAdapter.validateFilename(fileName)).not.toBe(null); done(); }); it('should also reject slashes in file names', done => { - const gridStoreAdapter = new GridStoreAdapter('mongodb://localhost:27017/parse'); + const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse'); const fileName = 'foo/randomFileName.pdf'; - expect(gridStoreAdapter.validateFilename(fileName)).not.toBe(null); + expect(gridFSAdapter.validateFilename(fileName)).not.toBe(null); done(); }); }); diff --git a/spec/GridFSBucketStorageAdapter.spec.js b/spec/GridFSBucketStorageAdapter.spec.js index 8431d6d7f5..7ffdced2bb 100644 --- a/spec/GridFSBucketStorageAdapter.spec.js +++ b/spec/GridFSBucketStorageAdapter.spec.js @@ -1,4 +1,3 @@ -const GridStoreAdapter = require('../lib/Adapters/Files/GridStoreAdapter').GridStoreAdapter; const GridFSBucketAdapter = require('../lib/Adapters/Files/GridFSBucketAdapter') .GridFSBucketAdapter; const { randomString } = require('../lib/cryptoUtils'); @@ -14,25 +13,13 @@ async function expectMissingFile(gfsAdapter, name) { } } -describe_only_db('mongo')('GridFSBucket and GridStore interop', () => { +describe_only_db('mongo')('GridFSBucket', () => { beforeEach(async () => { - const gsAdapter = new GridStoreAdapter(databaseURI); + const gsAdapter = new GridFSBucketAdapter(databaseURI); const db = await gsAdapter._connect(); await db.dropDatabase(); }); - it('a file created in GridStore should be available in GridFS', async () => { - const gsAdapter = new GridStoreAdapter(databaseURI); - const gfsAdapter = new GridFSBucketAdapter(databaseURI); - await expectMissingFile(gfsAdapter, 'myFileName'); - const originalString = 'abcdefghi'; - await gsAdapter.createFile('myFileName', originalString); - const gsResult = await gsAdapter.getFileData('myFileName'); - expect(gsResult.toString('utf8')).toBe(originalString); - const gfsResult = await gfsAdapter.getFileData('myFileName'); - expect(gfsResult.toString('utf8')).toBe(originalString); - }); - it('should save an encrypted file that can only be decrypted by a GridFS adapter with the encryptionKey', async () => { const unencryptedAdapter = new GridFSBucketAdapter(databaseURI); const encryptedAdapter = new GridFSBucketAdapter( @@ -451,7 +438,7 @@ describe_only_db('mongo')('GridFSBucket and GridStore interop', () => { await db.admin().serverStatus(); expect(false).toBe(true); } catch (e) { - expect(e.message).toEqual('topology was destroyed'); + expect(e.message).toEqual('MongoClient must be connected to perform this operation'); } }); }); diff --git a/spec/GridStoreAdapter.spec.js b/spec/GridStoreAdapter.spec.js deleted file mode 100644 index 145b8e0e6d..0000000000 --- a/spec/GridStoreAdapter.spec.js +++ /dev/null @@ -1,111 +0,0 @@ -const MongoClient = require('mongodb').MongoClient; -const GridStore = require('mongodb').GridStore; - -const GridStoreAdapter = require('../lib/Adapters/Files/GridStoreAdapter').GridStoreAdapter; -const Config = require('../lib/Config'); -const FilesController = require('../lib/Controllers/FilesController').default; - -// Small additional tests to improve overall coverage -describe_only_db('mongo')('GridStoreAdapter', () => { - it('should properly instanciate the GridStore when deleting a file', async done => { - const databaseURI = 'mongodb://localhost:27017/parse'; - const config = Config.get(Parse.applicationId); - const gridStoreAdapter = new GridStoreAdapter(databaseURI); - const db = await gridStoreAdapter._connect(); - await db.dropDatabase(); - const filesController = new FilesController(gridStoreAdapter, Parse.applicationId, {}); - - // save original unlink before redefinition - const originalUnlink = GridStore.prototype.unlink; - - let gridStoreMode; - - // new unlink method that will capture the mode in which GridStore was opened - GridStore.prototype.unlink = function () { - // restore original unlink during first call - GridStore.prototype.unlink = originalUnlink; - - gridStoreMode = this.mode; - - return originalUnlink.call(this); - }; - - filesController - .createFile(config, 'myFilename.txt', 'my file content', 'text/plain') - .then(myFile => { - return MongoClient.connect(databaseURI) - .then(client => { - const database = client.db(client.s.options.dbName); - // Verify the existance of the fs.files document - return database - .collection('fs.files') - .count() - .then(count => { - expect(count).toEqual(1); - return { database, client }; - }); - }) - .then(({ database, client }) => { - // Verify the existance of the fs.files document - return database - .collection('fs.chunks') - .count() - .then(count => { - expect(count).toEqual(1); - return client.close(); - }); - }) - .then(() => { - return filesController.deleteFile(config, myFile.name); - }); - }) - .then(() => { - return MongoClient.connect(databaseURI) - .then(client => { - const database = client.db(client.s.options.dbName); - // Verify the existance of the fs.files document - return database - .collection('fs.files') - .count() - .then(count => { - expect(count).toEqual(0); - return { database, client }; - }); - }) - .then(({ database, client }) => { - // Verify the existance of the fs.files document - return database - .collection('fs.chunks') - .count() - .then(count => { - expect(count).toEqual(0); - return client.close(); - }); - }); - }) - .then(() => { - // Verify that gridStore was opened in read only mode - expect(gridStoreMode).toEqual('r'); - - done(); - }) - .catch(fail); - }); - - it('handleShutdown, close connection', async () => { - const databaseURI = 'mongodb://localhost:27017/parse'; - const gridStoreAdapter = new GridStoreAdapter(databaseURI); - - const db = await gridStoreAdapter._connect(); - const status = await db.admin().serverStatus(); - expect(status.connections.current > 0).toEqual(true); - - await gridStoreAdapter.handleShutdown(); - try { - await db.admin().serverStatus(); - expect(false).toBe(true); - } catch (e) { - expect(e.message).toEqual('topology was destroyed'); - } - }); -}); diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index f6d2866417..a31a6134f7 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -1,7 +1,7 @@ 'use strict'; const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter').default; -const { MongoClient } = require('mongodb'); +const { MongoClient, Collection } = require('mongodb'); const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; const request = require('../lib/request'); const Config = require('../lib/Config'); @@ -101,7 +101,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { done.fail('Find succeeded despite taking too long!'); }, err => { - expect(err.name).toEqual('MongoError'); + expect(err.name).toEqual('MongoServerError'); expect(err.code).toEqual(50); expect(err.message).toMatch('operation exceeded time limit'); done(); @@ -283,7 +283,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { await adapter.database.admin().serverStatus(); expect(false).toBe(true); } catch (e) { - expect(e.message).toEqual('topology was destroyed'); + expect(e.message).toEqual('MongoClient must be connected to perform this operation'); } }); @@ -392,8 +392,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { const myObject = new Parse.Object('MyObject'); await myObject.save(); - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough(); + spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough(); await request({ method: 'POST', @@ -412,9 +411,9 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { }); let found = false; - databaseAdapter.database.serverConfig.command.calls.all().forEach(call => { + Collection.prototype.findOneAndUpdate.calls.all().forEach(call => { found = true; - expect(call.args[2].session.transaction.state).not.toBe('NO_TRANSACTION'); + expect(call.args[2].session.transaction.state).toBe('TRANSACTION_COMMITTED'); }); expect(found).toBe(true); }); @@ -423,8 +422,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { const myObject = new Parse.Object('MyObject'); await myObject.save(); - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough(); + spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough(); await request({ method: 'POST', @@ -443,9 +441,9 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { }); let found = false; - databaseAdapter.database.serverConfig.command.calls.all().forEach(call => { + Collection.prototype.findOneAndUpdate.calls.all().forEach(call => { found = true; - expect(call.args[2].session).toBe(undefined); + expect(call.args[2].session).toBeFalsy(); }); expect(found).toBe(true); }); @@ -454,8 +452,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { const myObject = new Parse.Object('MyObject'); await myObject.save(); - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough(); + spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough(); await request({ method: 'POST', @@ -473,9 +470,9 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { }); let found = false; - databaseAdapter.database.serverConfig.command.calls.all().forEach(call => { + Collection.prototype.findOneAndUpdate.calls.all().forEach(call => { found = true; - expect(call.args[2].session).toBe(undefined); + expect(call.args[2].session).toBeFalsy(); }); expect(found).toBe(true); }); @@ -484,8 +481,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { const myObject = new Parse.Object('MyObject'); await myObject.save(); - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'command').and.callThrough(); + spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough(); await request({ method: 'PUT', @@ -495,30 +491,28 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { }); let found = false; - databaseAdapter.database.serverConfig.command.calls.all().forEach(call => { + Collection.prototype.findOneAndUpdate.calls.all().forEach(call => { found = true; - expect(call.args[2].session).toBe(undefined); + expect(call.args[2].session).toBeFalsy(); }); expect(found).toBe(true); }); it('should not use transactions when using SDK insert', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'insert').and.callThrough(); + spyOn(Collection.prototype, 'insertOne').and.callThrough(); const myObject = new Parse.Object('MyObject'); await myObject.save(); - const calls = databaseAdapter.database.serverConfig.insert.calls.all(); + const calls = Collection.prototype.insertOne.calls.all(); expect(calls.length).toBeGreaterThan(0); calls.forEach(call => { - expect(call.args[2].session.transaction.state).toBe('NO_TRANSACTION'); + expect(call.args[1].session).toBeFalsy(); }); }); it('should not use transactions when using SDK update', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'update').and.callThrough(); + spyOn(Collection.prototype, 'findOneAndUpdate').and.callThrough(); const myObject = new Parse.Object('MyObject'); await myObject.save(); @@ -526,26 +520,25 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { myObject.set('myAttribute', 'myValue'); await myObject.save(); - const calls = databaseAdapter.database.serverConfig.update.calls.all(); + const calls = Collection.prototype.findOneAndUpdate.calls.all(); expect(calls.length).toBeGreaterThan(0); calls.forEach(call => { - expect(call.args[2].session.transaction.state).toBe('NO_TRANSACTION'); + expect(call.args[2].session).toBeFalsy(); }); }); it('should not use transactions when using SDK delete', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'remove').and.callThrough(); + spyOn(Collection.prototype, 'deleteMany').and.callThrough(); const myObject = new Parse.Object('MyObject'); await myObject.save(); await myObject.destroy(); - const calls = databaseAdapter.database.serverConfig.remove.calls.all(); + const calls = Collection.prototype.deleteMany.calls.all(); expect(calls.length).toBeGreaterThan(0); calls.forEach(call => { - expect(call.args[2].session.transaction.state).toBe('NO_TRANSACTION'); + expect(call.args[1].session).toBeFalsy(); }); }); }); diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 6541092b97..32a526132a 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -32,7 +32,7 @@ const { } = require('graphql'); const { ParseServer } = require('../'); const { ParseGraphQLServer } = require('../lib/GraphQL/ParseGraphQLServer'); -const ReadPreference = require('mongodb').ReadPreference; +const { ReadPreference, Collection } = require('mongodb'); const { v4: uuidv4 } = require('uuid'); function handleError(e) { @@ -4473,8 +4473,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -4498,13 +4497,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.PRIMARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.object.s.readPreference.mode).toBe(ReadPreference.PRIMARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.PRIMARY); + expect(call.object.s.readPreference.mode).toBe(ReadPreference.PRIMARY); } }); @@ -4520,8 +4519,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -4545,13 +4543,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); } }); @@ -4564,8 +4562,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -4592,13 +4589,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.NEAREST); + expect(call.args[1].readPreference).toBe(ReadPreference.NEAREST); } }); @@ -5456,8 +5453,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -5482,13 +5478,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.PRIMARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.object.s.readPreference.mode).toBe(ReadPreference.PRIMARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.PRIMARY); + expect(call.object.s.readPreference.mode).toBe(ReadPreference.PRIMARY); } }); @@ -5501,8 +5497,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -5527,13 +5522,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); } }); @@ -5546,8 +5541,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -5574,13 +5568,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.NEAREST); + expect(call.args[1].readPreference).toBe(ReadPreference.NEAREST); } }); @@ -5594,8 +5588,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); - const databaseAdapter = parseServer.config.databaseController.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await apolloClient.query({ query: gql` @@ -5632,13 +5625,13 @@ describe('ParseGraphQLServer', () => { let foundGraphQLClassReadPreference = false; let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('GraphQLClass') >= 0) { foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.SECONDARY); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { + expect(call.args[1].readPreference).toBe(ReadPreference.SECONDARY); + } else if (call.object.s.namespace.collection.indexOf('_User') >= 0) { foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.NEAREST); + expect(call.args[1].readPreference).toBe(ReadPreference.NEAREST); } }); diff --git a/spec/ReadPreferenceOption.spec.js b/spec/ReadPreferenceOption.spec.js index f2bc328d99..535c35c8b0 100644 --- a/spec/ReadPreferenceOption.spec.js +++ b/spec/ReadPreferenceOption.spec.js @@ -1,9 +1,8 @@ 'use strict'; const Parse = require('parse/node'); -const ReadPreference = require('mongodb').ReadPreference; +const { ReadPreference, Collection } = require('mongodb'); const request = require('../lib/request'); -const Config = require('../lib/Config'); function waitForReplication() { return new Promise(function (resolve) { @@ -13,8 +12,6 @@ function waitForReplication() { describe_only_db('mongo')('Read preference option', () => { it('should find in primary by default', done => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); @@ -22,7 +19,7 @@ describe_only_db('mongo')('Read preference option', () => { Parse.Object.saveAll([obj0, obj1]) .then(() => { - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); const query = new Parse.Query('MyObject'); query.equalTo('boolKey', false); @@ -31,10 +28,10 @@ describe_only_db('mongo')('Read preference option', () => { expect(results.length).toBe(1); expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { myObjectReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.PRIMARY); + expect(call.object.s.readPreference.mode).toBe(ReadPreference.PRIMARY); } }); @@ -58,15 +55,13 @@ describe_only_db('mongo')('Read preference option', () => { databaseAdapter: new MongoStorageAdapter(adapterOptions), }); - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); const query = new Parse.Query('MyObject'); query.equalTo('boolKey', false); @@ -76,10 +71,10 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { myObjectReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe(ReadPreference.NEAREST); + expect(call.args[1].readPreference).toBe(ReadPreference.NEAREST); } }); @@ -87,15 +82,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference in the beforeFind trigger', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -110,9 +103,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -120,15 +113,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should check read preference as case insensitive', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'sEcOnDarY'; @@ -144,9 +135,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -154,15 +145,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference in the beforeFind trigger even changing query', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.query.equalTo('boolKey', true); @@ -178,9 +167,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(true); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -188,15 +177,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference in the beforeFind trigger even returning query', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -216,9 +203,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(true); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -226,15 +213,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference in the beforeFind trigger even returning promise', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -253,9 +238,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(true); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -263,15 +248,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference to PRIMARY_PREFERRED', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'PRIMARY_PREFERRED'; @@ -286,9 +269,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -296,15 +279,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference to SECONDARY_PREFERRED', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -319,9 +300,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -329,15 +310,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference to NEAREST', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'NEAREST'; @@ -352,9 +331,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(results[0].get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -362,15 +341,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for GET', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -383,9 +360,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(result.get('boolKey')).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -393,15 +370,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for GET using API', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -421,9 +396,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(body.boolKey).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -431,15 +406,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for GET directly from API', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await waitForReplication(); const response = await request({ @@ -454,9 +427,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(response.data.boolKey).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -464,15 +437,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for GET using API through the beforeFind overriding API option', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -491,9 +462,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(response.data.boolKey).toBe(false); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -501,15 +472,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for FIND using API through beforeFind trigger', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -528,9 +497,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(response.data.results.length).toEqual(2); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -538,15 +507,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for FIND directly from API', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await waitForReplication(); const response = await request({ @@ -561,9 +528,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(response.data.results.length).toEqual(2); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -571,15 +538,13 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change read preference for FIND using API through the beforeFind overriding API option', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); await Parse.Object.saveAll([obj0, obj1]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -598,9 +563,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(response.data.results.length).toEqual(2); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -608,15 +573,13 @@ describe_only_db('mongo')('Read preference option', () => { }); xit('should change read preference for count', done => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject'); obj1.set('boolKey', true); Parse.Object.saveAll([obj0, obj1]).then(() => { - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject', req => { req.readPreference = 'SECONDARY'; @@ -631,9 +594,9 @@ describe_only_db('mongo')('Read preference option', () => { expect(result).toBe(1); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); @@ -659,17 +622,16 @@ describe_only_db('mongo')('Read preference option', () => { await waitForReplication(); // Spy on DB adapter - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'startSession').and.callThrough(); + spyOn(Collection.prototype, 'aggregate').and.callThrough(); // Query const query = new Parse.Query('MyObject'); const results = await query.aggregate([{ match: { boolKey: false } }]); // Validate expect(results.length).toBe(1); let readPreference = null; - databaseAdapter.database.serverConfig.startSession.calls.all().forEach(call => { - if (call.args[0].owner.ns.indexOf('MyObject') > -1) { - readPreference = call.args[0].owner.operation.readPreference.mode; + Collection.prototype.aggregate.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') > -1) { + readPreference = call.args[1].readPreference; } }); expect(readPreference).toEqual(ReadPreference.SECONDARY); @@ -685,8 +647,7 @@ describe_only_db('mongo')('Read preference option', () => { await waitForReplication(); // Spy on DB adapter - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); // Query const query = new Parse.Query('MyObject'); query.equalTo('boolKey', false); @@ -695,9 +656,9 @@ describe_only_db('mongo')('Read preference option', () => { // Validate expect(results.length).toBe(1); let myObjectReadPreference = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject') >= 0) { - myObjectReadPreference = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') >= 0) { + myObjectReadPreference = call.args[1].readPreference; } }); expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY); @@ -713,8 +674,7 @@ describe_only_db('mongo')('Read preference option', () => { await waitForReplication(); // Spy on DB adapter - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - spyOn(databaseAdapter.database.serverConfig, 'startSession').and.callThrough(); + spyOn(Collection.prototype, 'aggregate').and.callThrough(); // Query const query = new Parse.Query('MyObject'); query.readPreference('SECONDARY'); @@ -722,17 +682,15 @@ describe_only_db('mongo')('Read preference option', () => { // Validate expect(results.length).toBe(1); let readPreference = null; - databaseAdapter.database.serverConfig.startSession.calls.all().forEach(call => { - if (call.args[0].owner.ns.indexOf('MyObject') > -1) { - readPreference = call.args[0].owner.operation.readPreference.mode; + Collection.prototype.aggregate.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject') > -1) { + readPreference = call.args[1].readPreference; } }); expect(readPreference).toEqual(ReadPreference.SECONDARY); }); it('should find includes in same replica of readPreference by default', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -743,7 +701,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject2', req => { req.readPreference = 'SECONDARY'; @@ -765,15 +723,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -783,8 +741,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change includes read preference', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -795,7 +751,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject2', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -818,15 +774,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -836,8 +792,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change includes read preference when finding through API', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -848,7 +802,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await waitForReplication(); const response = await request({ @@ -873,15 +827,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -891,8 +845,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change includes read preference when getting through API', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -903,7 +855,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await waitForReplication(); const response = await request({ @@ -929,15 +881,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -947,8 +899,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should find subqueries in same replica of readPreference by default', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -959,7 +909,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject2', req => { req.readPreference = 'SECONDARY'; @@ -982,15 +932,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -1000,8 +950,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change subqueries read preference when using matchesQuery', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -1012,7 +960,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject2', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -1036,15 +984,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -1054,8 +1002,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change subqueries read preference when using doesNotMatchQuery', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -1066,7 +1012,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject2', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -1090,15 +1036,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -1108,8 +1054,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change subqueries read preference when using matchesKeyInQuery and doesNotMatchKeyInQuery', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -1120,7 +1064,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); Parse.Cloud.beforeFind('MyObject2', req => { req.readPreference = 'SECONDARY_PREFERRED'; @@ -1145,15 +1089,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); @@ -1163,8 +1107,6 @@ describe_only_db('mongo')('Read preference option', () => { }); it('should change subqueries read preference when using matchesKeyInQuery and doesNotMatchKeyInQuery to find through API', async () => { - const databaseAdapter = Config.get(Parse.applicationId).database.adapter; - const obj0 = new Parse.Object('MyObject0'); obj0.set('boolKey', false); const obj1 = new Parse.Object('MyObject1'); @@ -1175,7 +1117,7 @@ describe_only_db('mongo')('Read preference option', () => { obj2.set('myObject1', obj1); await Parse.Object.saveAll([obj0, obj1, obj2]); - spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough(); + spyOn(Collection.prototype, 'find').and.callThrough(); await waitForReplication(); const whereString = JSON.stringify({ @@ -1215,15 +1157,15 @@ describe_only_db('mongo')('Read preference option', () => { let myObjectReadPreference0 = null; let myObjectReadPreference1 = null; let myObjectReadPreference2 = null; - databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => { - if (call.args[0].ns.collection.indexOf('MyObject0') >= 0) { - myObjectReadPreference0 = call.args[0].options.readPreference.mode; + Collection.prototype.find.calls.all().forEach(call => { + if (call.object.s.namespace.collection.indexOf('MyObject0') >= 0) { + myObjectReadPreference0 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject1') >= 0) { - myObjectReadPreference1 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject1') >= 0) { + myObjectReadPreference1 = call.args[1].readPreference; } - if (call.args[0].ns.collection.indexOf('MyObject2') >= 0) { - myObjectReadPreference2 = call.args[0].options.readPreference.mode; + if (call.object.s.namespace.collection.indexOf('MyObject2') >= 0) { + myObjectReadPreference2 = call.args[1].readPreference; } }); diff --git a/src/Adapters/Files/GridFSBucketAdapter.js b/src/Adapters/Files/GridFSBucketAdapter.js index 84876fad6f..06896e73b5 100644 --- a/src/Adapters/Files/GridFSBucketAdapter.js +++ b/src/Adapters/Files/GridFSBucketAdapter.js @@ -1,6 +1,6 @@ /** GridFSBucketAdapter - Stores files in Mongo using GridStore + Stores files in Mongo using GridFS Requires the database adapter to be based on mongoclient @flow weak diff --git a/src/Adapters/Files/GridStoreAdapter.js b/src/Adapters/Files/GridStoreAdapter.js index ca3166af98..39d1ca41c6 100644 --- a/src/Adapters/Files/GridStoreAdapter.js +++ b/src/Adapters/Files/GridStoreAdapter.js @@ -1,181 +1,4 @@ -/** - GridStoreAdapter - Stores files in Mongo using GridStore - Requires the database adapter to be based on mongoclient - (GridStore is deprecated, Please use GridFSBucket instead) - - @flow weak - */ - -// @flow-disable-next -import { MongoClient, GridStore, Db } from 'mongodb'; -import { FilesAdapter, validateFilename } from './FilesAdapter'; -import defaults from '../../defaults'; - -export class GridStoreAdapter extends FilesAdapter { - _databaseURI: string; - _connectionPromise: Promise; - _mongoOptions: Object; - - constructor(mongoDatabaseURI = defaults.DefaultMongoURI, mongoOptions = {}) { - super(); - this._databaseURI = mongoDatabaseURI; - - const defaultMongoOptions = { - useNewUrlParser: true, - useUnifiedTopology: true, - }; - this._mongoOptions = Object.assign(defaultMongoOptions, mongoOptions); - } - - _connect() { - if (!this._connectionPromise) { - this._connectionPromise = MongoClient.connect(this._databaseURI, this._mongoOptions).then( - client => { - this._client = client; - return client.db(client.s.options.dbName); - } - ); - } - return this._connectionPromise; - } - - // For a given config object, filename, and data, store a file - // Returns a promise - createFile(filename: string, data) { - return this._connect() - .then(database => { - const gridStore = new GridStore(database, filename, 'w'); - return gridStore.open(); - }) - .then(gridStore => { - return gridStore.write(data); - }) - .then(gridStore => { - return gridStore.close(); - }); - } - - deleteFile(filename: string) { - return this._connect() - .then(database => { - const gridStore = new GridStore(database, filename, 'r'); - return gridStore.open(); - }) - .then(gridStore => { - return gridStore.unlink(); - }) - .then(gridStore => { - return gridStore.close(); - }); - } - - getFileData(filename: string) { - return this._connect() - .then(database => { - return GridStore.exist(database, filename).then(() => { - const gridStore = new GridStore(database, filename, 'r'); - return gridStore.open(); - }); - }) - .then(gridStore => { - return gridStore.read(); - }); - } - - getFileLocation(config, filename) { - return config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename); - } - - async handleFileStream(filename: string, req, res, contentType) { - const stream = await this._connect().then(database => { - return GridStore.exist(database, filename).then(() => { - const gridStore = new GridStore(database, filename, 'r'); - return gridStore.open(); - }); - }); - handleRangeRequest(stream, req, res, contentType); - } - - handleShutdown() { - if (!this._client) { - return Promise.resolve(); - } - return this._client.close(false); - } - - validateFilename(filename) { - return validateFilename(filename); - } -} - -// handleRangeRequest is licensed under Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/). -// Author: LEROIB at weightingformypizza (https://weightingformypizza.wordpress.com/2015/06/24/stream-html5-media-content-like-video-audio-from-mongodb-using-express-and-gridstore/). -function handleRangeRequest(stream, req, res, contentType) { - const buffer_size = 1024 * 1024; //1024Kb - // Range request, partial stream the file - const parts = req - .get('Range') - .replace(/bytes=/, '') - .split('-'); - let [start, end] = parts; - const notEnded = !end && end !== 0; - const notStarted = !start && start !== 0; - // No end provided, we want all bytes - if (notEnded) { - end = stream.length - 1; - } - // No start provided, we're reading backwards - if (notStarted) { - start = stream.length - end; - end = start + end - 1; - } - - // Data exceeds the buffer_size, cap - if (end - start >= buffer_size) { - end = start + buffer_size - 1; - } - - const contentLength = end - start + 1; - - res.writeHead(206, { - 'Content-Range': 'bytes ' + start + '-' + end + '/' + stream.length, - 'Accept-Ranges': 'bytes', - 'Content-Length': contentLength, - 'Content-Type': contentType, - }); - - stream.seek(start, function () { - // Get gridFile stream - const gridFileStream = stream.stream(true); - let bufferAvail = 0; - let remainingBytesToWrite = contentLength; - let totalBytesWritten = 0; - // Write to response - gridFileStream.on('data', function (data) { - bufferAvail += data.length; - if (bufferAvail > 0) { - // slice returns the same buffer if overflowing - // safe to call in any case - const buffer = data.slice(0, remainingBytesToWrite); - // Write the buffer - res.write(buffer); - // Increment total - totalBytesWritten += buffer.length; - // Decrement remaining - remainingBytesToWrite -= data.length; - // Decrement the available buffer - bufferAvail -= buffer.length; - } - // In case of small slices, all values will be good at that point - // we've written enough, end... - if (totalBytesWritten >= contentLength) { - stream.close(); - res.end(); - this.destroy(); - } - }); - }); -} - -export default GridStoreAdapter; +// Note: GridStore was replaced by GridFSBucketAdapter by default in 2018 by @flovilmart +throw new Error( + 'GridStoreAdapter: GridStore is no longer supported by parse server and mongodb, use GridFSBucketAdapter instead.' +); diff --git a/src/Adapters/Storage/Mongo/MongoSchemaCollection.js b/src/Adapters/Storage/Mongo/MongoSchemaCollection.js index 78284503fc..20e3eec325 100644 --- a/src/Adapters/Storage/Mongo/MongoSchemaCollection.js +++ b/src/Adapters/Storage/Mongo/MongoSchemaCollection.js @@ -177,7 +177,7 @@ class MongoSchemaCollection { insertSchema(schema: any) { return this._collection .insertOne(schema) - .then(result => mongoSchemaToParseSchema(result.ops[0])) + .then(() => mongoSchemaToParseSchema(schema)) .catch(error => { if (error.code === 11000) { //Mongo's duplicate key error diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index c1fe63ba9b..93e23b91c3 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -479,6 +479,7 @@ export class MongoStorageAdapter implements StorageAdapter { const mongoObject = parseObjectToMongoObjectForCreate(className, object, schema); return this._adaptiveCollection(className) .then(collection => collection.insertOne(mongoObject, transactionalSession)) + .then(() => ({ ops: [mongoObject] })) .catch(error => { if (error.code === 11000) { // Duplicate value @@ -517,8 +518,8 @@ export class MongoStorageAdapter implements StorageAdapter { }) .catch(err => this.handleError(err)) .then( - ({ result }) => { - if (result.n === 0) { + ({ deletedCount }) => { + if (deletedCount === 0) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); } return Promise.resolve(); From 1e05309e7900cdeb945b39d42538a04423389dde Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 6 Feb 2022 17:31:41 +0000 Subject: [PATCH 60/83] chore(release): 5.0.0-alpha.22 [skip ci] # [5.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.21...5.0.0-alpha.22) (2022-02-06) ### Features * upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a)) ### BREAKING CHANGES * The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. ([f88aa2a](f88aa2a)) --- changelogs/CHANGELOG_alpha.md | 12 ++++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index a78e3f0637..524c2cb949 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,15 @@ +# [5.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.21...5.0.0-alpha.22) (2022-02-06) + + +### Features + +* upgrade to MongoDB Node.js driver 4.x for MongoDB 5.0 support ([#7794](https://github.com/parse-community/parse-server/issues/7794)) ([f88aa2a](https://github.com/parse-community/parse-server/commit/f88aa2a62a533e5344d1c13dd38c5a0b283a480a)) + + +### BREAKING CHANGES + +* The MongoDB GridStore adapter has been removed. By default, Parse Server already uses GridFS, so if you do not manually use the GridStore adapter, you can ignore this change. ([f88aa2a](f88aa2a)) + # [5.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.20...5.0.0-alpha.21) (2022-01-25) diff --git a/package-lock.json b/package-lock.json index 045195ff54..ccc18f4831 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.21", + "version": "5.0.0-alpha.22", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8129cb2f19..0abd1e1b23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.21", + "version": "5.0.0-alpha.22", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 08089d6fcbb215412448ce7d92b21b9fe6c929f2 Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Mon, 7 Feb 2022 00:09:41 +0100 Subject: [PATCH 61/83] fix: server crash using GraphQL due to missing @apollo/client peer dependency (#7787) --- package-lock.json | 34 ++++++++-------------------------- package.json | 2 +- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index ccc18f4831..0ae5227cb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "version": "3.4.17", "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.4.17.tgz", "integrity": "sha512-MDt2rwMX1GqodiVEKJqmDmAz8xr0qJmq5PdWeIt0yDaT4GOkKYWZiWkyfhfv3raTk8PyJvbsNG9q2CqmUrlGfg==", - "dev": true, "requires": { "@graphql-typed-document-node/core": "^3.0.0", "@wry/context": "^0.6.0", @@ -34,7 +33,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.2.tgz", "integrity": "sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA==", - "dev": true, "requires": { "tslib": "^2.3.0" } @@ -43,7 +41,6 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.3.tgz", "integrity": "sha512-HinBlTbFslQI0OHP07JLsSXPibSegec6r9ai5xxq/qHYCsIQbzpymLpDhAUsnXcSrDEcd0L62L8vsOEdzM0qlA==", - "dev": true, "requires": { "tslib": "^2.1.0" } @@ -51,14 +48,12 @@ "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "zen-observable-ts": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", - "dev": true, "requires": { "@types/zen-observable": "0.8.3", "zen-observable": "0.8.15" @@ -1467,8 +1462,7 @@ "@graphql-typed-document-node/core": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", - "dev": true + "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==" }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -2690,8 +2684,7 @@ "@types/zen-observable": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==", - "dev": true + "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, "@typescript-eslint/types": { "version": "4.31.0", @@ -2771,7 +2764,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz", "integrity": "sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw==", - "dev": true, "requires": { "tslib": "^2.3.0" }, @@ -2779,8 +2771,7 @@ "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" } } }, @@ -2803,7 +2794,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.1.tgz", "integrity": "sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw==", - "dev": true, "requires": { "tslib": "^2.3.0" }, @@ -2811,8 +2801,7 @@ "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" } } }, @@ -7716,7 +7705,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dev": true, "requires": { "react-is": "^16.7.0" } @@ -8884,8 +8872,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -9819,7 +9806,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -13305,7 +13291,6 @@ "version": "0.16.1", "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz", "integrity": "sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg==", - "dev": true, "requires": { "@wry/context": "^0.6.0", "@wry/trie": "^0.3.0" @@ -14129,7 +14114,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -14277,8 +14261,7 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-native-crypto-js": { "version": "1.0.0", @@ -15973,8 +15956,7 @@ "symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", - "dev": true + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==" }, "table": { "version": "5.4.6", diff --git a/package.json b/package.json index 0abd1e1b23..b544d4ea0f 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "dependencies": { "@apollographql/graphql-playground-html": "1.6.29", "@graphql-tools/links": "8.2.1", + "@apollo/client": "3.4.17", "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", "@parse/fs-files-adapter": "1.2.1", @@ -62,7 +63,6 @@ }, "devDependencies": { "@actions/core": "1.2.6", - "@apollo/client": "3.4.17", "@babel/cli": "7.10.0", "@babel/core": "7.10.0", "@babel/plugin-proposal-object-rest-spread": "7.10.0", From 43cc97d99fa7346739f9e376a22afe3d95439b4c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 6 Feb 2022 23:10:52 +0000 Subject: [PATCH 62/83] chore(release): 5.0.0-alpha.23 [skip ci] # [5.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.22...5.0.0-alpha.23) (2022-02-06) ### Bug Fixes * server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 524c2cb949..531ed30bef 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.22...5.0.0-alpha.23) (2022-02-06) + + +### Bug Fixes + +* server crash using GraphQL due to missing @apollo/client peer dependency ([#7787](https://github.com/parse-community/parse-server/issues/7787)) ([08089d6](https://github.com/parse-community/parse-server/commit/08089d6fcbb215412448ce7d92b21b9fe6c929f2)) + # [5.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.21...5.0.0-alpha.22) (2022-02-06) diff --git a/package-lock.json b/package-lock.json index 0ae5227cb1..19b210fcbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.22", + "version": "5.0.0-alpha.23", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b544d4ea0f..3f7832f7a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.22", + "version": "5.0.0-alpha.23", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From c6b20320399f6467f09195c3c839493dc72fd603 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Tue, 8 Feb 2022 12:02:45 +0200 Subject: [PATCH 63/83] refactor: upgrade @apollo/client from 3.4.17 to 3.5.7 (#7797) --- package-lock.json | 36 +++++++++++++++--------------------- package.json | 2 +- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 19b210fcbc..f75a7ed473 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dev": true }, "@apollo/client": { - "version": "3.4.17", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.4.17.tgz", - "integrity": "sha512-MDt2rwMX1GqodiVEKJqmDmAz8xr0qJmq5PdWeIt0yDaT4GOkKYWZiWkyfhfv3raTk8PyJvbsNG9q2CqmUrlGfg==", + "version": "3.5.7", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.5.7.tgz", + "integrity": "sha512-HSLqTGp3sp/PVIWYLLr5v3fjQSr6Fxg6Z5RQj5Q9ALyseIVudD8GZk1jHplaUblTFMBueXGw3Z6DXObuVAr3tw==", "requires": { "@graphql-typed-document-node/core": "^3.0.0", "@wry/context": "^0.6.0", @@ -24,9 +24,9 @@ "optimism": "^0.16.1", "prop-types": "^15.7.2", "symbol-observable": "^4.0.0", - "ts-invariant": "^0.9.0", + "ts-invariant": "^0.9.4", "tslib": "^2.3.0", - "zen-observable-ts": "~1.1.0" + "zen-observable-ts": "^1.2.0" }, "dependencies": { "@wry/equality": { @@ -38,9 +38,9 @@ } }, "ts-invariant": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.3.tgz", - "integrity": "sha512-HinBlTbFslQI0OHP07JLsSXPibSegec6r9ai5xxq/qHYCsIQbzpymLpDhAUsnXcSrDEcd0L62L8vsOEdzM0qlA==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.4.tgz", + "integrity": "sha512-63jtX/ZSwnUNi/WhXjnK8kz4cHHpYS60AnmA6ixz17l7E12a5puCWFlNpkne5Rl0J8TBPVHpGjsj4fxs8ObVLQ==", "requires": { "tslib": "^2.1.0" } @@ -51,11 +51,10 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "zen-observable-ts": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", - "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.3.tgz", + "integrity": "sha512-hc/TGiPkAWpByykMwDcem3SdUgA4We+0Qb36bItSuJC9xD0XVBZoFHYoadAomDSNf64CG8Ydj0Qb8Od8BUWz5g==", "requires": { - "@types/zen-observable": "0.8.3", "zen-observable": "0.8.15" } } @@ -2681,11 +2680,6 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, - "@types/zen-observable": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" - }, "@typescript-eslint/types": { "version": "4.31.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.0.tgz", @@ -14111,13 +14105,13 @@ "dev": true }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "proto-list": { diff --git a/package.json b/package.json index 3f7832f7a2..41a1983477 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "@apollographql/graphql-playground-html": "1.6.29", "@graphql-tools/links": "8.2.1", - "@apollo/client": "3.4.17", + "@apollo/client": "3.5.7", "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", "@parse/fs-files-adapter": "1.2.1", From fc9d77f1d45c9c81c40faf14c4e33db9b685cc9d Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Wed, 9 Feb 2022 20:07:53 +0200 Subject: [PATCH 64/83] refactor: upgrade jwks-rsa from 1.12.3 to 2.0.5 (#7800) --- package-lock.json | 80 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index f75a7ed473..aff8788591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1819,6 +1819,11 @@ "@octokit/openapi-types": "^11.2.0" } }, + "@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==" + }, "@parse/fs-files-adapter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.1.tgz", @@ -2392,7 +2397,8 @@ "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true }, "@types/accepts": { "version": "1.3.5", @@ -2839,6 +2845,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "requires": { "debug": "4" }, @@ -2847,6 +2854,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -2854,7 +2862,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, @@ -3480,14 +3489,6 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -7784,6 +7785,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, "requires": { "@tootallnate/once": "1", "agent-base": "6", @@ -7794,6 +7796,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -7801,7 +7804,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, @@ -7819,6 +7823,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -7828,6 +7833,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -7835,7 +7841,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, @@ -8863,6 +8870,14 @@ } } }, + "jose": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", + "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", + "requires": { + "@panva/asn1.js": "^1.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9065,41 +9080,29 @@ } }, "jwks-rsa": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.12.3.tgz", - "integrity": "sha512-cFipFDeYYaO9FhhYJcZWX/IyZgc0+g316rcHnDpT2dNRNIE/lMOmWKKqp09TkJoYlNFzrEVODsR4GgXJMgWhnA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.0.5.tgz", + "integrity": "sha512-fliHfsiBRzEU0nXzSvwnh0hynzGB0WihF+CinKbSRlaqRxbqqKf2xbBPgwc8mzf18/WgwlG8e5eTpfSTBcU4DQ==", "requires": { "@types/express-jwt": "0.0.42", - "axios": "^0.21.1", - "debug": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "jsonwebtoken": "^8.5.1", + "debug": "^4.3.2", + "jose": "^2.0.5", "limiter": "^1.1.5", - "lru-memoizer": "^2.1.2", - "ms": "^2.1.2", - "proxy-from-env": "^1.1.0" + "lru-memoizer": "^2.1.4" }, "dependencies": { "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } } }, "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -14129,11 +14132,6 @@ "ipaddr.js": "1.9.1" } }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, "ps-node": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ps-node/-/ps-node-0.1.6.tgz", diff --git a/package.json b/package.json index 41a1983477..7309a60782 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "graphql-upload": "11.0.0", "intersect": "1.0.1", "jsonwebtoken": "8.5.1", - "jwks-rsa": "1.12.3", + "jwks-rsa": "2.0.5", "ldapjs": "2.3.1", "lodash": "4.17.21", "lru-cache": "5.1.1", From 70088a95a78393da2a4ac68be81e63107747626a Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Thu, 10 Feb 2022 13:10:14 +0200 Subject: [PATCH 65/83] fix: security upgrade follow-redirects from 1.14.7 to 1.14.8 (#7801) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index aff8788591..d32b3e3f7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7031,9 +7031,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index 7309a60782..362b4b5b84 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "cors": "2.8.5", "deepcopy": "2.1.0", "express": "4.17.2", - "follow-redirects": "1.14.7", + "follow-redirects": "1.14.8", "graphql": "15.7.1", "graphql-list-fields": "2.0.2", "graphql-relay": "0.7.0", From d678a43696bd4c59fbc625097dcfbeb8d619f564 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 10 Feb 2022 11:11:17 +0000 Subject: [PATCH 66/83] chore(release): 5.0.0-alpha.24 [skip ci] # [5.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.23...5.0.0-alpha.24) (2022-02-10) ### Bug Fixes * security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 531ed30bef..802392c576 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.23...5.0.0-alpha.24) (2022-02-10) + + +### Bug Fixes + +* security upgrade follow-redirects from 1.14.7 to 1.14.8 ([#7801](https://github.com/parse-community/parse-server/issues/7801)) ([70088a9](https://github.com/parse-community/parse-server/commit/70088a95a78393da2a4ac68be81e63107747626a)) + # [5.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.22...5.0.0-alpha.23) (2022-02-06) diff --git a/package-lock.json b/package-lock.json index d32b3e3f7e..64ef86344b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.23", + "version": "5.0.0-alpha.24", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 362b4b5b84..d2eb1c3ab3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.23", + "version": "5.0.0-alpha.24", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 82c3015dc09071d555b85e1c08b7eecb68fea1c9 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 13 Feb 2022 12:14:57 +0200 Subject: [PATCH 67/83] refactor: upgrade @parse/push-adapter from 3.4.1 to 4.1.0 (#7810) --- package-lock.json | 22 +++++++++++----------- package.json | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 64ef86344b..e65b0502f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1836,9 +1836,9 @@ "dev": true }, "@parse/node-apn": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-4.1.1.tgz", - "integrity": "sha512-stWlQE95w5T0vkVYscoq/S3eXPQ1qzdQbKKQ8GAdw4CSNxRWLWgOH50byUR30thnQ93RshLCH5ROkvXMqzzLtw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.0.tgz", + "integrity": "sha512-WT3iVwr1Y/Jf4nq4RGNwBdLwm3gTodsb+g3IY98MPSJ7LCNf+R81Nj/nQO5r/twJfN1v5B8cAgfvPGs2rPelvg==", "requires": { "debug": "4.3.2", "jsonwebtoken": "8.5.1", @@ -1872,11 +1872,11 @@ } }, "@parse/push-adapter": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-3.4.1.tgz", - "integrity": "sha512-iev69kbwhXbez5nfEwB2GkCWBLUmRlImQTmHPpLnHBJfATYKyXf/H41WQhBPuwwScZBVp9ABsIsjjKy8iKg3fw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-4.1.0.tgz", + "integrity": "sha512-8SOU4zgIr3+wn6Hbge4X/zAYAcJR7puJ3aY2ri+8fqMARgBria4JkIeAyKaTG/mUMHw6Qy5DpYYRe0LjImjZNw==", "requires": { - "@parse/node-apn": "4.1.1", + "@parse/node-apn": "5.1.0", "@parse/node-gcm": "1.0.2", "npmlog": "4.1.2", "parse": "3.3.0" @@ -16769,11 +16769,11 @@ "dev": true }, "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "winston": { diff --git a/package.json b/package.json index d2eb1c3ab3..8c7868f668 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", "@parse/fs-files-adapter": "1.2.1", - "@parse/push-adapter": "3.4.1", + "@parse/push-adapter": "4.1.0", "apollo-server-express": "2.25.2", "bcryptjs": "2.4.3", "body-parser": "1.19.1", From b6a20d9e9f0b87655a397cf089c13867ff472d57 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Mon, 14 Feb 2022 11:13:35 +0200 Subject: [PATCH 68/83] refactor: upgrade winston from 3.3.3 to 3.4.0 (#7812) --- package-lock.json | 88 +++++++++++++++++++++++++++++------------------ package.json | 2 +- 2 files changed, 56 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index e65b0502f6..63389fdcf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1172,10 +1172,15 @@ "to-fast-properties": "^2.0.0" } }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + }, "@dabh/diagnostics": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", - "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", "requires": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -3444,7 +3449,8 @@ "async": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", - "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==" + "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==", + "dev": true }, "async-each": { "version": "1.0.3", @@ -4495,12 +4501,12 @@ } }, "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "color-convert": "^1.9.3", + "color-string": "^1.6.0" } }, "color-convert": { @@ -4517,9 +4523,9 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", - "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -4534,14 +4540,15 @@ "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true }, "colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", "requires": { - "color": "3.0.x", + "color": "^3.1.3", "text-hex": "1.0.x" } }, @@ -6685,11 +6692,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fast-safe-stringify": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz", - "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==" - }, "fastq": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", @@ -9771,14 +9773,14 @@ } }, "logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.0.tgz", + "integrity": "sha512-CPSJw4ftjf517EhXZGGvTHHkYobo7ZCc0kvwUoOYcjfR2UVrI66RHj8MCrfAdEitdmFqbu2BYdYs8FHHZSb6iw==", "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", + "@colors/colors": "1.5.0", "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" }, "dependencies": { @@ -14764,6 +14766,11 @@ "ret": "~0.1.10" } }, + "safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -16777,21 +16784,26 @@ } }, "winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.4.0.tgz", + "integrity": "sha512-FqilVj+5HKwCfIHQzMxrrd5tBIH10JTS3koFGbLVWBODjiIYq7zir08rFyBT4rrTYG/eaTqDcfSIbcjSM78YSw==", "requires": { "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", + "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.2.0", + "logform": "^2.3.2", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" + "winston-transport": "^4.4.2" }, "dependencies": { + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -16801,6 +16813,16 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + } } } }, diff --git a/package.json b/package.json index 8c7868f668..dc845d0400 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", "uuid": "8.3.2", - "winston": "3.3.3", + "winston": "3.4.0", "winston-daily-rotate-file": "4.5.5", "ws": "8.2.3" }, From 7a30d7c885975768663f674bc0245c21f7391aa7 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Tue, 15 Feb 2022 13:42:13 +0200 Subject: [PATCH 69/83] refactor: upgrade lru-cache from 5.1.1 to 6.0.0 (#7813) --- package-lock.json | 15 ++++----------- package.json | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63389fdcf8..7dde7b8a04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9824,18 +9824,11 @@ "dev": true }, "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "requires": { - "yallist": "^3.0.2" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } + "yallist": "^4.0.0" } }, "lru-memoizer": { diff --git a/package.json b/package.json index dc845d0400..e248eb639b 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "jwks-rsa": "2.0.5", "ldapjs": "2.3.1", "lodash": "4.17.21", - "lru-cache": "5.1.1", + "lru-cache": "6.0.0", "mime": "3.0.0", "mongodb": "4.3.1", "mustache": "4.2.0", From 8cece4a2a8daf1f5b4b2d8be456d3051cf6317c3 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Thu, 17 Feb 2022 00:48:05 +0200 Subject: [PATCH 70/83] refactor: upgrade @apollo/client from 3.5.7 to 3.5.8 (#7814) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7dde7b8a04..ae36a9f186 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dev": true }, "@apollo/client": { - "version": "3.5.7", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.5.7.tgz", - "integrity": "sha512-HSLqTGp3sp/PVIWYLLr5v3fjQSr6Fxg6Z5RQj5Q9ALyseIVudD8GZk1jHplaUblTFMBueXGw3Z6DXObuVAr3tw==", + "version": "3.5.8", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.5.8.tgz", + "integrity": "sha512-MAm05+I1ullr64VLpZwon/ISnkMuNLf6vDqgo9wiMhHYBGT4yOAbAIseRdjCHZwfSx/7AUuBgaTNOssZPIr6FQ==", "requires": { "@graphql-typed-document-node/core": "^3.0.0", "@wry/context": "^0.6.0", diff --git a/package.json b/package.json index e248eb639b..e6013636af 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "@apollographql/graphql-playground-html": "1.6.29", "@graphql-tools/links": "8.2.1", - "@apollo/client": "3.5.7", + "@apollo/client": "3.5.8", "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", "@parse/fs-files-adapter": "1.2.1", From c7012012aa2f2db78795e9ddd4a5386cd9474f1f Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Fri, 18 Feb 2022 22:44:52 +0200 Subject: [PATCH 71/83] refactor: upgrade winston-daily-rotate-file from 4.5.5 to 4.6.0 (#7816) --- package-lock.json | 39 ++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae36a9f186..75e974b7f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6809,11 +6809,11 @@ } }, "file-stream-rotator": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.5.7.tgz", - "integrity": "sha512-VYb3HZ/GiAGUCrfeakO8Mp54YGswNUHvL7P09WQcXAJNSj3iQ5QraYSp3cIn1MUyw6uzfgN/EFOarCNa4JvUHQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", + "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==", "requires": { - "moment": "^2.11.2" + "moment": "^2.29.1" } }, "file-type": { @@ -16820,23 +16820,36 @@ } }, "winston-daily-rotate-file": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.5.tgz", - "integrity": "sha512-ds0WahIjiDhKCiMXmY799pDBW+58ByqIBtUcsqr4oDoXrAI3Zn+hbgFdUxzMfqA93OG0mPLYVMiotqTgE/WeWQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.6.0.tgz", + "integrity": "sha512-mvpFb1LYmTvh/vz0dIS/aDCwEm0cvDa8D/tE4xWwdUYolD250wf+n0y1PZ2xr7fbvTLF/PQYqXtFIFrmog03Ow==", "requires": { - "file-stream-rotator": "^0.5.7", + "file-stream-rotator": "^0.6.1", "object-hash": "^2.0.1", "triple-beam": "^1.3.0", "winston-transport": "^4.4.0" } }, "winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", "requires": { - "readable-stream": "^2.3.7", - "triple-beam": "^1.2.0" + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "word-wrap": { diff --git a/package.json b/package.json index e6013636af..af42248868 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "tv4": "1.3.0", "uuid": "8.3.2", "winston": "3.4.0", - "winston-daily-rotate-file": "4.5.5", + "winston-daily-rotate-file": "4.6.0", "ws": "8.2.3" }, "devDependencies": { From 2a6cec173ed68c8c0d4a9f22b3940db98aa07664 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Sun, 20 Feb 2022 19:26:13 +0200 Subject: [PATCH 72/83] refactor: upgrade winston from 3.4.0 to 3.5.0 (#7817) --- package-lock.json | 17 ++++------------- package.json | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 75e974b7f2..cea8f637a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16777,9 +16777,9 @@ } }, "winston": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.4.0.tgz", - "integrity": "sha512-FqilVj+5HKwCfIHQzMxrrd5tBIH10JTS3koFGbLVWBODjiIYq7zir08rFyBT4rrTYG/eaTqDcfSIbcjSM78YSw==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.5.0.tgz", + "integrity": "sha512-OQMbmLsIdVHvm2hSurrYZs+iZNIImXneYJ6pX7LseSMEq20HdTETXiNnNX3FDwN4LB/xDRZLF6JYOY+AI112Kw==", "requires": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", @@ -16787,6 +16787,7 @@ "logform": "^2.3.2", "one-time": "^1.0.0", "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.4.2" @@ -16806,16 +16807,6 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } - }, - "winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", - "requires": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - } } } }, diff --git a/package.json b/package.json index af42248868..9ef5f5171a 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", "uuid": "8.3.2", - "winston": "3.4.0", + "winston": "3.5.0", "winston-daily-rotate-file": "4.6.0", "ws": "8.2.3" }, From 4af253d1f8654a6f57b5137ad310cdacadc922cc Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Wed, 23 Feb 2022 02:55:33 +0200 Subject: [PATCH 73/83] fix: upgrade winston from 3.5.0 to 3.5.1 (#7820) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index cea8f637a9..6cdd789da5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16777,9 +16777,9 @@ } }, "winston": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.5.0.tgz", - "integrity": "sha512-OQMbmLsIdVHvm2hSurrYZs+iZNIImXneYJ6pX7LseSMEq20HdTETXiNnNX3FDwN4LB/xDRZLF6JYOY+AI112Kw==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.5.1.tgz", + "integrity": "sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA==", "requires": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", diff --git a/package.json b/package.json index 9ef5f5171a..98b67ea48d 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", "uuid": "8.3.2", - "winston": "3.5.0", + "winston": "3.5.1", "winston-daily-rotate-file": "4.6.0", "ws": "8.2.3" }, From 9806912045ae651fce66db38b3b6f5e798e14139 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 23 Feb 2022 00:56:33 +0000 Subject: [PATCH 74/83] chore(release): 5.0.0-alpha.25 [skip ci] # [5.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.24...5.0.0-alpha.25) (2022-02-23) ### Bug Fixes * upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 802392c576..5c684b3697 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.24...5.0.0-alpha.25) (2022-02-23) + + +### Bug Fixes + +* upgrade winston from 3.5.0 to 3.5.1 ([#7820](https://github.com/parse-community/parse-server/issues/7820)) ([4af253d](https://github.com/parse-community/parse-server/commit/4af253d1f8654a6f57b5137ad310cdacadc922cc)) + # [5.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.23...5.0.0-alpha.24) (2022-02-10) diff --git a/package-lock.json b/package-lock.json index 6cdd789da5..34c0c9e20a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.24", + "version": "5.0.0-alpha.25", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 98b67ea48d..38809766de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.24", + "version": "5.0.0-alpha.25", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 5ca228882332b65f3ac05407e6e4da1ee3ef3749 Mon Sep 17 00:00:00 2001 From: Snyk bot Date: Fri, 25 Feb 2022 18:56:29 +0200 Subject: [PATCH 75/83] fix: package.json & package-lock.json to reduce vulnerabilities (#7823) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-NODEFETCH-2342118 --- package-lock.json | 103 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34c0c9e20a..abce4b4295 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1198,20 +1198,20 @@ } }, "@graphql-tools/batch-execute": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.3.1.tgz", - "integrity": "sha512-63kHY8ZdoO5FoeDXYHnAak1R3ysMViMPwWC2XUblFckuVLMUPmB2ONje8rjr2CvzWBHAW8c1Zsex+U3xhKtGIA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.3.2.tgz", + "integrity": "sha512-ICWqM+MvEkIPHm18Q0cmkvm134zeQMomBKmTRxyxMNhL/ouz6Nqld52/brSlaHnzA3fczupeRJzZ0YatruGBcQ==", "requires": { - "@graphql-tools/utils": "^8.5.1", + "@graphql-tools/utils": "^8.6.2", "dataloader": "2.0.0", "tslib": "~2.3.0", "value-or-promise": "1.0.11" }, "dependencies": { "@graphql-tools/utils": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.5.3.tgz", - "integrity": "sha512-HDNGWFVa8QQkoQB0H1lftvaO1X5xUaUDk1zr1qDe0xN1NL0E/CrQdJ5UKLqOvH4hkqVUPxQsyOoAZFkaH6rLHg==", + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.2.tgz", + "integrity": "sha512-x1DG0cJgpJtImUlNE780B/dfp8pxvVxOD6UeykFH5rHes26S4kGokbgU8F1IgrJ1vAPm/OVBHtd2kicTsPfwdA==", "requires": { "tslib": "~2.3.0" } @@ -1242,63 +1242,64 @@ } }, "@graphql-tools/links": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/links/-/links-8.2.1.tgz", - "integrity": "sha512-J0igz42eKh/RQxDZPdEE4YiztY3zWTBcsn/bUtJp52XKNj0EIO0fR6WLEocT6uxgWCNnWYPOQUaf7bEgeW44Vg==", - "requires": { - "@graphql-tools/delegate": "^8.4.1", - "@graphql-tools/utils": "^8.5.1", - "apollo-upload-client": "16.0.0", - "cross-fetch": "3.1.4", - "form-data": "4.0.0", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/links/-/links-8.2.2.tgz", + "integrity": "sha512-lWyRvG4KqVj/3dpuQzZN34TXs9+5ETaT1MxhPHe6LIF/DdNQk4Q4Y7VeET/fZ8ZhbzgweMy0AA+ZkrS2HxBcgw==", + "requires": { + "@graphql-tools/delegate": "^8.5.1", + "@graphql-tools/utils": "^8.6.2", + "apollo-upload-client": "17.0.0", + "form-data": "^4.0.0", + "node-fetch": "^2.6.5", "tslib": "~2.3.0" }, "dependencies": { "@graphql-tools/delegate": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.4.2.tgz", - "integrity": "sha512-CjggOhiL4WtyG2I3kux+1/p8lQxSFHBj0gwa0NxnQ6Vsnpw7Ig5VP1ovPnitFuBv2k4QdC37Nj2xv2n7DRn8fw==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.5.1.tgz", + "integrity": "sha512-/YPmVxitt57F8sH50pnfXASzOOjEfaUDkX48eF5q6f16+JBncej2zeu+Zm2c68q8MbIxhPlEGfpd0QZeqTvAxw==", "requires": { - "@graphql-tools/batch-execute": "^8.3.1", - "@graphql-tools/schema": "^8.3.1", - "@graphql-tools/utils": "^8.5.3", + "@graphql-tools/batch-execute": "^8.3.2", + "@graphql-tools/schema": "^8.3.2", + "@graphql-tools/utils": "^8.6.2", "dataloader": "2.0.0", + "graphql-executor": "0.0.18", "tslib": "~2.3.0", "value-or-promise": "1.0.11" } }, "@graphql-tools/merge": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.1.tgz", - "integrity": "sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.3.tgz", + "integrity": "sha512-XCSmL6/Xg8259OTWNp69B57CPWiVL69kB7pposFrufG/zaAlI9BS68dgzrxmmSqZV5ZHU4r/6Tbf6fwnEJGiSw==", "requires": { - "@graphql-tools/utils": "^8.5.1", + "@graphql-tools/utils": "^8.6.2", "tslib": "~2.3.0" } }, "@graphql-tools/schema": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.1.tgz", - "integrity": "sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.2.tgz", + "integrity": "sha512-77feSmIuHdoxMXRbRyxE8rEziKesd/AcqKV6fmxe7Zt+PgIQITxNDew2XJJg7qFTMNM43W77Ia6njUSBxNOkwg==", "requires": { - "@graphql-tools/merge": "^8.2.1", - "@graphql-tools/utils": "^8.5.1", + "@graphql-tools/merge": "^8.2.3", + "@graphql-tools/utils": "^8.6.2", "tslib": "~2.3.0", "value-or-promise": "1.0.11" } }, "@graphql-tools/utils": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.5.3.tgz", - "integrity": "sha512-HDNGWFVa8QQkoQB0H1lftvaO1X5xUaUDk1zr1qDe0xN1NL0E/CrQdJ5UKLqOvH4hkqVUPxQsyOoAZFkaH6rLHg==", + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.2.tgz", + "integrity": "sha512-x1DG0cJgpJtImUlNE780B/dfp8pxvVxOD6UeykFH5rHes26S4kGokbgU8F1IgrJ1vAPm/OVBHtd2kicTsPfwdA==", "requires": { "tslib": "~2.3.0" } }, "apollo-upload-client": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-16.0.0.tgz", - "integrity": "sha512-aLhYucyA0T8aBEQ5g+p13qnR9RUyL8xqb8FSZ7e/Kw2KUOsotLUlFluLobqaE7JSUFwc6sKfXIcwB7y4yEjbZg==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-17.0.0.tgz", + "integrity": "sha512-pue33bWVbdlXAGFPkgz53TTmxVMrKeQr0mdRcftNY+PoHIdbGZD0hoaXHvO6OePJAkFz7OiCFUf98p1G/9+Ykw==", "requires": { "extract-files": "^11.0.0" } @@ -1313,6 +1314,14 @@ "mime-types": "^2.1.12" } }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -4838,21 +4847,6 @@ "cross-spawn": "^7.0.1" } }, - "cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "requires": { - "node-fetch": "2.6.1" - }, - "dependencies": { - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - } - } - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7453,6 +7447,11 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.7.1.tgz", "integrity": "sha512-x34S6gC0/peBZnlK60zCJox/d45A7p6At9oN9EPA3qhoIAlR4LNZmXRLkICBckwwTMJzVdA8cx3QIQZMOl606A==" }, + "graphql-executor": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/graphql-executor/-/graphql-executor-0.0.18.tgz", + "integrity": "sha512-upUSl7tfZCZ5dWG1XkOvpG70Yk3duZKcCoi/uJso4WxJVT6KIrcK4nZ4+2X/hzx46pL8wAukgYHY6iNmocRN+g==" + }, "graphql-extensions": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.15.0.tgz", diff --git a/package.json b/package.json index 38809766de..daf95b9d7f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "license": "BSD-3-Clause", "dependencies": { "@apollographql/graphql-playground-html": "1.6.29", - "@graphql-tools/links": "8.2.1", + "@graphql-tools/links": "8.2.2", "@apollo/client": "3.5.8", "@graphql-tools/stitch": "6.2.4", "@graphql-tools/utils": "6.2.4", From ad5d17953ba0e8378bdc421ef3769bb3469d60ad Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 25 Feb 2022 16:57:59 +0000 Subject: [PATCH 76/83] chore(release): 5.0.0-alpha.26 [skip ci] # [5.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.25...5.0.0-alpha.26) (2022-02-25) ### Bug Fixes * package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 5c684b3697..b9f983147c 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.25...5.0.0-alpha.26) (2022-02-25) + + +### Bug Fixes + +* package.json & package-lock.json to reduce vulnerabilities ([#7823](https://github.com/parse-community/parse-server/issues/7823)) ([5ca2288](https://github.com/parse-community/parse-server/commit/5ca228882332b65f3ac05407e6e4da1ee3ef3749)) + # [5.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.24...5.0.0-alpha.25) (2022-02-23) diff --git a/package-lock.json b/package-lock.json index abce4b4295..eb1d59955a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.25", + "version": "5.0.0-alpha.26", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index daf95b9d7f..8def283675 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.25", + "version": "5.0.0-alpha.26", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 8a126fc1a23e8534c884cab0a846335754b4d6d6 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 25 Feb 2022 15:01:15 -0800 Subject: [PATCH 77/83] Update node engine to 2.22.0 (#7827) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8def283675..bae61c61f4 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "madge:circular": "node_modules/.bin/madge ./src --circular" }, "engines": { - "node": ">=12.20.0 <17" + "node": ">=12.22.0 <17" }, "bin": { "parse-server": "bin/parse-server" From f235412c1b6c2b173b7531f285429ea7214b56a2 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 12 Mar 2022 14:13:38 +0100 Subject: [PATCH 78/83] revert: update node engine to 2.22.0 (#7827) This reverts commit 8a126fc1a23e8534c884cab0a846335754b4d6d6. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bae61c61f4..8def283675 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "madge:circular": "node_modules/.bin/madge ./src --circular" }, "engines": { - "node": ">=12.22.0 <17" + "node": ">=12.20.0 <17" }, "bin": { "parse-server": "bin/parse-server" From 6bc021ee1430b843deb9b8429b8b51fd697fc3d6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 12 Mar 2022 13:14:36 +0000 Subject: [PATCH 79/83] chore(release): 5.0.0-alpha.27 [skip ci] # [5.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.26...5.0.0-alpha.27) (2022-03-12) ### Reverts * update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index b9f983147c..9aca837bbd 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.26...5.0.0-alpha.27) (2022-03-12) + + +### Reverts + +* update node engine to 2.22.0 ([#7827](https://github.com/parse-community/parse-server/issues/7827)) ([f235412](https://github.com/parse-community/parse-server/commit/f235412c1b6c2b173b7531f285429ea7214b56a2)) + # [5.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.25...5.0.0-alpha.26) (2022-02-25) diff --git a/package-lock.json b/package-lock.json index eb1d59955a..702b206a80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.26", + "version": "5.0.0-alpha.27", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8def283675..10739ee606 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.26", + "version": "5.0.0-alpha.27", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From 972b800ae4d8dc3eda81bc62789da4eb97ba8c23 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 12 Mar 2022 14:30:59 +0100 Subject: [PATCH 80/83] docs: add revert commit instructions to CONTRIBUTING guide (#7845) --- CONTRIBUTING.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1605c47ec3..ddc99a811a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,6 +22,8 @@ - [Pull Request](#pull-request) - [Breaking Change](#breaking-change) - [Merging](#merging) + - [Breaking Change](#breaking-change-1) + - [Reverting](#reverting) - [Versioning](#versioning) - [Code of Conduct](#code-of-conduct) @@ -335,8 +337,13 @@ If a pull request contains a braking change, the description of the pull request The following guide is for anyone who merges a contributor pull request into the working branch, the working branch into a release branch, a release branch into another release branch, or any other direct commits such as hotfixes into release branches or the working branch. -- For changelog generation, only the commit message set when merging the pull request is relevant. The title and description of the GitHub pull request as authored by the contributor have no influence on the changelog generation. However, the title of the GitHub pull request should be used as the commit message. -- If the pull request contains a breaking change, the commit message must contain the phrase `BREAKING CHANGE`, capitalized and without any formatting, followed by a short description of the breaking change and ideally how the developer should address it, all in a single line. This line should contain more details focusing on the "breaking” aspect of the change and is intended to assist the developer in adapting. Keep it concise, as it will become part of the changelog entry, for example: +- A contributor pull request must be merged into the working branch using `Squash and Merge`, to create a single commit message that describes the change. +- A release branch or the default branch must be merged into another release branch using `Merge Commit`, to preserve each individual commit message that describes its respective change. +- For changelog generation, only the commit message set when merging the pull request is relevant. The title and description of the GitHub pull request as authored by the contributor have no influence on the changelog generation. However, the title of the GitHub pull request should be used as the commit message. See the following chapters for considerations in special scenarios, e.g. merging a breaking change or reverting a commit. + +### Breaking Change + +If the pull request contains a breaking change, the commit message must contain the phrase `BREAKING CHANGE`, capitalized and without any formatting, followed by a short description of the breaking change and ideally how the developer should address it, all in a single line. This line should contain more details focusing on the "breaking” aspect of the change and is intended to assist the developer in adapting. Keep it concise, as it will become part of the changelog entry, for example: ``` fix: remove handle from door @@ -344,8 +351,16 @@ The following guide is for anyone who merges a contributor pull request into the BREAKING CHANGE: You cannot open the door anymore by using a handle. See the [#migration guide](http://example.com) for more details. ``` Keep in mind that in a repository with release automation, merging such a commit message will trigger a release with a major version increment. -- A contributor pull request must be merged into the working branch using `Squash and Merge`, to create a single commit message that describes the change. -- A release branch or the default branch must be merged into another release branch using `Merge Commit`, to preserve each individual commit message that describes its respective change. + +### Reverting + +If the commit reverts a previous commit, use the prefix `revert:`, followed by the header of the reverted commit. In the body of the commit message add `This reverts commit .`, where the hash is the SHA of the commit being reverted. For example: + + ``` + revert: fix: remove handle from door + + This reverts commit 1234567890abcdef. + ``` ## Versioning From e569f402b1fd8648fb0d1523b71b2a03273902a5 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Sat, 12 Mar 2022 14:47:23 +0100 Subject: [PATCH 81/83] fix: security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) (#7844) --- .madgerc | 10 + resources/buildConfigDefinitions.js | 14 ++ spec/vulnerabilities.spec.js | 283 ++++++++++++++++++++++++++ src/Config.js | 12 +- src/Controllers/DatabaseController.js | 107 ++++++---- src/Controllers/index.js | 4 +- src/Options/Definitions.js | 18 ++ src/Options/docs.js | 1 + src/Options/index.js | 7 + src/RestWrite.js | 14 ++ src/Utils.js | 26 +++ 11 files changed, 450 insertions(+), 46 deletions(-) create mode 100644 .madgerc create mode 100644 spec/vulnerabilities.spec.js diff --git a/.madgerc b/.madgerc new file mode 100644 index 0000000000..4b9aa24bc2 --- /dev/null +++ b/.madgerc @@ -0,0 +1,10 @@ +{ + "detectiveOptions": { + "ts": { + "skipTypeImports": true + }, + "es6": { + "skipTypeImports": true + } + } +} diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index 52ff3ac7a8..670aafad38 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -172,6 +172,20 @@ function parseDefaultValue(elt, value, t) { literalValue = t.arrayExpression(array.map((value) => { if (typeof value == 'string') { return t.stringLiteral(value); + } else if (typeof value == 'number') { + return t.numericLiteral(value); + } else if (typeof value == 'object') { + const object = parsers.objectParser(value); + const props = Object.entries(object).map(([k, v]) => { + if (typeof v == 'string') { + return t.objectProperty(t.identifier(k), t.stringLiteral(v)); + } else if (typeof v == 'number') { + return t.objectProperty(t.identifier(k), t.numericLiteral(v)); + } else if (typeof v == 'boolean') { + return t.objectProperty(t.identifier(k), t.booleanLiteral(v)); + } + }); + return t.objectExpression(props); } else { throw new Error('Unable to parse array'); } diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js new file mode 100644 index 0000000000..1255d64398 --- /dev/null +++ b/spec/vulnerabilities.spec.js @@ -0,0 +1,283 @@ +const request = require('../lib/request'); + +describe('Vulnerabilities', () => { + describe('Object prototype pollution', () => { + it('denies object prototype to be polluted with keyword "constructor"', async () => { + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const response = await request({ + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/PP', + body: JSON.stringify({ + obj: { + constructor: { + prototype: { + dummy: 0, + }, + }, + }, + }), + }).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe('Prohibited keyword in request data: {"key":"constructor"}.'); + expect(Object.prototype.dummy).toBeUndefined(); + }); + + it('denies object prototype to be polluted with keypath string "constructor"', async () => { + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const objResponse = await request({ + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/PP', + body: JSON.stringify({ + obj: {}, + }), + }).catch(e => e); + const pollResponse = await request({ + headers: headers, + method: 'PUT', + url: `http://localhost:8378/1/classes/PP/${objResponse.data.objectId}`, + body: JSON.stringify({ + 'obj.constructor.prototype.dummy': { + __op: 'Increment', + amount: 1, + }, + }), + }).catch(e => e); + expect(Object.prototype.dummy).toBeUndefined(); + expect(pollResponse.status).toBe(400); + const text = JSON.parse(pollResponse.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe('Prohibited keyword in request data: {"key":"constructor"}.'); + expect(Object.prototype.dummy).toBeUndefined(); + }); + + it('denies object prototype to be polluted with keyword "__proto__"', async () => { + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const response = await request({ + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/PP', + body: JSON.stringify({ 'obj.__proto__.dummy': 0 }), + }).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe('Prohibited keyword in request data: {"key":"__proto__"}.'); + expect(Object.prototype.dummy).toBeUndefined(); + }); + }); + + describe('Request denylist', () => { + it('denies BSON type code data in write request by default', async () => { + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe( + 'Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.' + ); + }); + + it('allows BSON type code data in write request with custom denylist', async () => { + await reconfigureServer({ + requestKeywordDenylist: [], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(201); + const text = JSON.parse(response.text); + expect(text.objectId).toBeDefined(); + }); + + it('denies write request with custom denylist of key/value', async () => { + await reconfigureServer({ + requestKeywordDenylist: [{ key: 'a[K]ey', value: 'aValue[123]*' }], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + aKey: 'aValue321', + code: 'delete Object.prototype.evalFunctions', + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe( + 'Prohibited keyword in request data: {"key":"a[K]ey","value":"aValue[123]*"}.' + ); + }); + + it('denies write request with custom denylist of nested key/value', async () => { + await reconfigureServer({ + requestKeywordDenylist: [{ key: 'a[K]ey', value: 'aValue[123]*' }], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + nested: { + aKey: 'aValue321', + code: 'delete Object.prototype.evalFunctions', + }, + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe( + 'Prohibited keyword in request data: {"key":"a[K]ey","value":"aValue[123]*"}.' + ); + }); + + it('denies write request with custom denylist of key/value in array', async () => { + await reconfigureServer({ + requestKeywordDenylist: [{ key: 'a[K]ey', value: 'aValue[123]*' }], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: [ + { + aKey: 'aValue321', + code: 'delete Object.prototype.evalFunctions', + }, + ], + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe( + 'Prohibited keyword in request data: {"key":"a[K]ey","value":"aValue[123]*"}.' + ); + }); + + it('denies write request with custom denylist of key', async () => { + await reconfigureServer({ + requestKeywordDenylist: [{ key: 'a[K]ey' }], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + aKey: 'aValue321', + code: 'delete Object.prototype.evalFunctions', + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe('Prohibited keyword in request data: {"key":"a[K]ey"}.'); + }); + + it('denies write request with custom denylist of value', async () => { + await reconfigureServer({ + requestKeywordDenylist: [{ value: 'aValue[123]*' }], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + aKey: 'aValue321', + code: 'delete Object.prototype.evalFunctions', + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(400); + const text = JSON.parse(response.text); + expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); + expect(text.error).toBe('Prohibited keyword in request data: {"value":"aValue[123]*"}.'); + }); + }); +}); diff --git a/src/Config.js b/src/Config.js index 069b7e2a43..04834d3291 100644 --- a/src/Config.js +++ b/src/Config.js @@ -35,7 +35,7 @@ export class Config { config.applicationId = applicationId; Object.keys(cacheInfo).forEach(key => { if (key == 'databaseController') { - config.database = new DatabaseController(cacheInfo.databaseController.adapter); + config.database = new DatabaseController(cacheInfo.databaseController.adapter, config); } else { config[key] = cacheInfo[key]; } @@ -78,6 +78,7 @@ export class Config { security, enforcePrivateUsers, schema, + requestKeywordDenylist, }) { if (masterKey === readOnlyMasterKey) { throw new Error('masterKey and readOnlyMasterKey should be different'); @@ -116,6 +117,15 @@ export class Config { this.validateSecurityOptions(security); this.validateSchemaOptions(schema); this.validateEnforcePrivateUsers(enforcePrivateUsers); + this.validateRequestKeywordDenylist(requestKeywordDenylist); + } + + static validateRequestKeywordDenylist(requestKeywordDenylist) { + if (requestKeywordDenylist === undefined) { + requestKeywordDenylist = requestKeywordDenylist.default; + } else if (!Array.isArray(requestKeywordDenylist)) { + throw 'Parse Server option requestKeywordDenylist must be an array.'; + } } static validateEnforcePrivateUsers(enforcePrivateUsers) { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 2c313f83b4..f7322fc531 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -17,6 +17,7 @@ import MongoStorageAdapter from '../Adapters/Storage/Mongo/MongoStorageAdapter'; import PostgresStorageAdapter from '../Adapters/Storage/Postgres/PostgresStorageAdapter'; import SchemaCache from '../Adapters/Cache/SchemaCache'; import type { LoadSchemaOptions } from './types'; +import type { ParseServerOptions } from '../Options'; import type { QueryOptions, FullQueryOptions } from '../Adapters/Storage/StorageAdapter'; function addWriteACL(query, acl) { @@ -258,41 +259,6 @@ const isSpecialUpdateKey = key => { return specialKeysForUpdate.indexOf(key) >= 0; }; -function expandResultOnKeyPath(object, key, value) { - if (key.indexOf('.') < 0) { - object[key] = value[key]; - return object; - } - const path = key.split('.'); - const firstKey = path[0]; - const nextPath = path.slice(1).join('.'); - object[firstKey] = expandResultOnKeyPath(object[firstKey] || {}, nextPath, value[firstKey]); - delete object[key]; - return object; -} - -function sanitizeDatabaseResult(originalObject, result): Promise { - const response = {}; - if (!result) { - return Promise.resolve(response); - } - Object.keys(originalObject).forEach(key => { - const keyUpdate = originalObject[key]; - // determine if that was an op - if ( - keyUpdate && - typeof keyUpdate === 'object' && - keyUpdate.__op && - ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1 - ) { - // only valid ops that produce an actionable result - // the op may have happend on a keypath - expandResultOnKeyPath(response, key, result); - } - }); - return Promise.resolve(response); -} - function joinTableName(className, key) { return `_Join:${key}:${className}`; } @@ -395,17 +361,18 @@ const relationSchema = { class DatabaseController { adapter: StorageAdapter; - idempotencyOptions: any; schemaCache: any; schemaPromise: ?Promise; _transactionalSession: ?any; + options: ParseServerOptions; + idempotencyOptions: any; - constructor(adapter: StorageAdapter, idempotencyOptions?: Object = {}) { + constructor(adapter: StorageAdapter, options: ParseServerOptions) { this.adapter = adapter; - this.idempotencyOptions = idempotencyOptions; - // We don't want a mutable this.schema, because then you could have - // one request that uses different schemas for different parts of - // it. Instead, use loadSchema to get a schema. + this.options = options || {}; + this.idempotencyOptions = this.options.idempotencyOptions || {}; + // Prevent mutable this.schema, otherwise one request could use + // multiple schemas, so instead use loadSchema to get a schema. this.schemaPromise = null; this._transactionalSession = null; } @@ -646,7 +613,7 @@ class DatabaseController { if (skipSanitization) { return Promise.resolve(result); } - return sanitizeDatabaseResult(originalUpdate, result); + return this._sanitizeDatabaseResult(originalUpdate, result); }); }); } @@ -873,7 +840,7 @@ class DatabaseController { object, relationUpdates ).then(() => { - return sanitizeDatabaseResult(originalObject, result.ops[0]); + return this._sanitizeDatabaseResult(originalObject, result.ops[0]); }); }); }); @@ -1782,6 +1749,60 @@ class DatabaseController { await this.adapter.updateSchemaWithIndexes(); } + _expandResultOnKeyPath(object: any, key: string, value: any): any { + if (key.indexOf('.') < 0) { + object[key] = value[key]; + return object; + } + const path = key.split('.'); + const firstKey = path[0]; + const nextPath = path.slice(1).join('.'); + + // Scan request data for denied keywords + if (this.options && this.options.requestKeywordDenylist) { + // Scan request data for denied keywords + for (const keyword of this.options.requestKeywordDenylist) { + const isMatch = (a, b) => (typeof a === 'string' && new RegExp(a).test(b)) || a === b; + if (isMatch(firstKey, keyword.key)) { + throw new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ); + } + } + } + + object[firstKey] = this._expandResultOnKeyPath( + object[firstKey] || {}, + nextPath, + value[firstKey] + ); + delete object[key]; + return object; + } + + _sanitizeDatabaseResult(originalObject: any, result: any): Promise { + const response = {}; + if (!result) { + return Promise.resolve(response); + } + Object.keys(originalObject).forEach(key => { + const keyUpdate = originalObject[key]; + // determine if that was an op + if ( + keyUpdate && + typeof keyUpdate === 'object' && + keyUpdate.__op && + ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1 + ) { + // only valid ops that produce an actionable result + // the op may have happened on a keypath + this._expandResultOnKeyPath(response, key, result); + } + }); + return Promise.resolve(response); + } + static _validateQuery: any => void; } diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 152de684fe..b2feff0fc2 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -142,7 +142,7 @@ export function getLiveQueryController(options: ParseServerOptions): LiveQueryCo } export function getDatabaseController(options: ParseServerOptions): DatabaseController { - const { databaseURI, collectionPrefix, databaseOptions, idempotencyOptions } = options; + const { databaseURI, collectionPrefix, databaseOptions } = options; let { databaseAdapter } = options; if ( (databaseOptions || @@ -156,7 +156,7 @@ export function getDatabaseController(options: ParseServerOptions): DatabaseCont } else { databaseAdapter = loadAdapter(databaseAdapter); } - return new DatabaseController(databaseAdapter, idempotencyOptions); + return new DatabaseController(databaseAdapter, options); } export function getHooksController( diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index e2cbd17920..1edd704bd6 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -350,6 +350,24 @@ module.exports.ParseServerOptions = { env: 'PARSE_SERVER_READ_ONLY_MASTER_KEY', help: 'Read-only key, which has the same capabilities as MasterKey without writes', }, + requestKeywordDenylist: { + env: 'PARSE_SERVER_REQUEST_KEYWORD_DENYLIST', + help: + 'An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns.', + action: parsers.arrayParser, + default: [ + { + key: '_bsontype', + value: 'Code', + }, + { + key: 'constructor', + }, + { + key: '__proto__', + }, + ], + }, restAPIKey: { env: 'PARSE_SERVER_REST_API_KEY', help: 'Key for REST calls', diff --git a/src/Options/docs.js b/src/Options/docs.js index c6b2e1abf1..fc0ff3b799 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -64,6 +64,7 @@ * @property {String} publicServerURL Public URL to your parse server with http:// or https://. * @property {Any} push Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications * @property {String} readOnlyMasterKey Read-only key, which has the same capabilities as MasterKey without writes + * @property {RequestKeywordDenylist[]} requestKeywordDenylist An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns. * @property {String} restAPIKey Key for REST calls * @property {Boolean} revokeSessionOnPasswordReset When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions. * @property {Boolean} scheduledPush Configuration for push scheduling, defaults to false. diff --git a/src/Options/index.js b/src/Options/index.js index 31b9e10d41..3482d88c50 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -14,6 +14,10 @@ type Adapter = string | any | T; type NumberOrBoolean = number | boolean; type NumberOrString = number | string; type ProtectedFields = any; +type RequestKeywordDenylist = { + key: string | any, + value: any, +}; export interface ParseServerOptions { /* Your Parse Application ID @@ -252,6 +256,9 @@ export interface ParseServerOptions { /* Set to true if new users should be created without public read and write access. :DEFAULT: false */ enforcePrivateUsers: ?boolean; + /* An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns. + :DEFAULT: [{"key":"_bsontype","value":"Code"},{"key":"constructor"},{"key":"__proto__"}] */ + requestKeywordDenylist: ?(RequestKeywordDenylist[]); } export interface SecurityOptions { diff --git a/src/RestWrite.js b/src/RestWrite.js index a651cf9c6c..8b728731da 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -6,6 +6,7 @@ var SchemaController = require('./Controllers/SchemaController'); var deepcopy = require('deepcopy'); const Auth = require('./Auth'); +const Utils = require('./Utils'); var cryptoUtils = require('./cryptoUtils'); var passwordCrypto = require('./password'); var Parse = require('parse/node'); @@ -61,6 +62,19 @@ function RestWrite(config, auth, className, query, data, originalData, clientSDK } } + if (this.config.requestKeywordDenylist) { + // Scan request data for denied keywords + for (const keyword of this.config.requestKeywordDenylist) { + const match = Utils.objectContainsKeyValue(data, keyword.key, keyword.value); + if (match) { + throw new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ); + } + } + } + // When the operation is complete, this.response may have several // fields. // response: the actual data to be returned diff --git a/src/Utils.js b/src/Utils.js index c96be08495..399939a152 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -332,6 +332,32 @@ class Utils { }; } } + + /** + * Deep-scans an object for a matching key/value definition. + * @param {Object} obj The object to scan. + * @param {String | undefined} key The key to match, or undefined if only the value should be matched. + * @param {any | undefined} value The value to match, or undefined if only the key should be matched. + * @returns {Boolean} True if a match was found, false otherwise. + */ + static objectContainsKeyValue(obj, key, value) { + const isMatch = (a, b) => (typeof a === 'string' && new RegExp(a).test(b)) || a === b; + const isKeyMatch = k => isMatch(key, k); + const isValueMatch = v => isMatch(value, v); + for (const [k, v] of Object.entries(obj)) { + if (key !== undefined && value === undefined && isKeyMatch(k)) { + return true; + } else if (key === undefined && value !== undefined && isValueMatch(v)) { + return true; + } else if (key !== undefined && value !== undefined && isKeyMatch(k) && isValueMatch(v)) { + return true; + } + if (['[object Object]', '[object Array]'].includes(Object.prototype.toString.call(v))) { + return Utils.objectContainsKeyValue(v, key, value); + } + } + return false; + } } module.exports = Utils; From 9b344da9d08a18417d379111f1ac4cbfc3e46149 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 12 Mar 2022 13:48:37 +0000 Subject: [PATCH 82/83] chore(release): 5.0.0-alpha.28 [skip ci] # [5.0.0-alpha.28](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.27...5.0.0-alpha.28) (2022-03-12) ### Bug Fixes * security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5)) --- changelogs/CHANGELOG_alpha.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 9aca837bbd..21863e351e 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +# [5.0.0-alpha.28](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.27...5.0.0-alpha.28) (2022-03-12) + + +### Bug Fixes + +* security vulnerability that allows remote code execution (GHSA-p6h4-93qp-jhcm) ([#7844](https://github.com/parse-community/parse-server/issues/7844)) ([e569f40](https://github.com/parse-community/parse-server/commit/e569f402b1fd8648fb0d1523b71b2a03273902a5)) + # [5.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/5.0.0-alpha.26...5.0.0-alpha.27) (2022-03-12) diff --git a/package-lock.json b/package-lock.json index 702b206a80..ec5397acc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.27", + "version": "5.0.0-alpha.28", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 10739ee606..0cdc1c6fba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "5.0.0-alpha.27", + "version": "5.0.0-alpha.28", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { From b2f06323b56689793d16074bd481fd0f42afb9a2 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Sat, 12 Mar 2022 14:53:04 +0100 Subject: [PATCH 83/83] bump min node engine to 12.22.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0cdc1c6fba..8bbbb1720b 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "madge:circular": "node_modules/.bin/madge ./src --circular" }, "engines": { - "node": ">=12.20.0 <17" + "node": ">=12.22.10 <17" }, "bin": { "parse-server": "bin/parse-server"