Compare commits

..
637 Commits
Author SHA1 Message Date
semantic-release-bot 1979de03da chore(release): 7.2.0 [skip ci]
# [7.2.0](https://github.com/parse-community/parse-server/compare/7.1.0...7.2.0) (2024-07-09)

### Bug Fixes

* Invalid push notification tokens are not cleaned up from database for FCM API v2 ([#9173](https://github.com/parse-community/parse-server/issues/9173)) ([284da09](https://github.com/parse-community/parse-server/commit/284da09f4546356b37511a589fb5f64a3efffe79))

### Features

* Add support for dot notation on array fields of Parse Object ([#9115](https://github.com/parse-community/parse-server/issues/9115)) ([cf4c880](https://github.com/parse-community/parse-server/commit/cf4c8807b9da87a0a5f9c94e5bdfcf17cda80cf4))
* Upgrade to @parse/push-adapter 6.4.0 ([#9182](https://github.com/parse-community/parse-server/issues/9182)) ([ef1634b](https://github.com/parse-community/parse-server/commit/ef1634bf1f360429108d29b08032fc7961ff96a1))
* Upgrade to Parse JS SDK 5.3.0 ([#9180](https://github.com/parse-community/parse-server/issues/9180)) ([dca187f](https://github.com/parse-community/parse-server/commit/dca187f91b93cbb362b22a3fb9ee38451799ff13))
2024-07-09 01:03:57 +00:00
Manuel 6f2fc443c8 build: Release (#9189) 2024-07-09 03:02:22 +02:00
Manuel Trezza c696e1e044 empty 2024-07-09 02:37:26 +02:00
semantic-release-bot 70146bbdce chore(release): 7.2.0-beta.1 [skip ci]
# [7.2.0-beta.1](https://github.com/parse-community/parse-server/compare/7.1.0...7.2.0-beta.1) (2024-07-09)

### Bug Fixes

* Invalid push notification tokens are not cleaned up from database for FCM API v2 ([#9173](https://github.com/parse-community/parse-server/issues/9173)) ([284da09](https://github.com/parse-community/parse-server/commit/284da09f4546356b37511a589fb5f64a3efffe79))

### Features

* Add support for dot notation on array fields of Parse Object ([#9115](https://github.com/parse-community/parse-server/issues/9115)) ([cf4c880](https://github.com/parse-community/parse-server/commit/cf4c8807b9da87a0a5f9c94e5bdfcf17cda80cf4))
* Upgrade to @parse/push-adapter 6.4.0 ([#9182](https://github.com/parse-community/parse-server/issues/9182)) ([ef1634b](https://github.com/parse-community/parse-server/commit/ef1634bf1f360429108d29b08032fc7961ff96a1))
* Upgrade to Parse JS SDK 5.3.0 ([#9180](https://github.com/parse-community/parse-server/issues/9180)) ([dca187f](https://github.com/parse-community/parse-server/commit/dca187f91b93cbb362b22a3fb9ee38451799ff13))
2024-07-09 00:36:23 +00:00
Manuel 694da02ce7 build: Release (#9186) 2024-07-09 02:35:26 +02:00
Manuel Trezza e1d4d122b6 Merge branch 'release' into build 2024-07-09 02:22:24 +02:00
Manuel 68922c89bc refactor: Upgrade semantic release (#9185) 2024-07-09 02:10:50 +02:00
mkmandar123 1e21b69376 test: Object data type should not change from beforeSave to afterSave trigger (#9177) 2024-07-09 00:07:02 +02:00
semantic-release-bot 3353998edd chore(release): 7.1.0-alpha.16 [skip ci]
# [7.1.0-alpha.16](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.15...7.1.0-alpha.16) (2024-07-08)

### Features

* Add support for dot notation on array fields of Parse Object ([#9115](https://github.com/parse-community/parse-server/issues/9115)) ([cf4c880](https://github.com/parse-community/parse-server/commit/cf4c8807b9da87a0a5f9c94e5bdfcf17cda80cf4))
2024-07-08 21:30:50 +00:00
Diamond Lewis cf4c8807b9 feat: Add support for dot notation on array fields of Parse Object (#9115) 2024-07-08 23:29:58 +02:00
dependabot[bot] 892052cc44 refactor: Bump @node-rs/bcrypt from 1.10.1 to 1.10.4 (#9175) 2024-07-08 23:06:21 +02:00
Diamond Lewis a6e0a1d4a6 test: Remove unnecessary setTimeout and reconfigureServer calls (#9183) 2024-07-08 23:05:43 +02:00
Manuel 28c4330c89 refactor: Upgrade to @parse/push-adapter 6.4.1 (#9184) 2024-07-08 23:03:48 +02:00
semantic-release-bot c764203ce8 chore(release): 7.1.0-alpha.15 [skip ci]
# [7.1.0-alpha.15](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.14...7.1.0-alpha.15) (2024-07-08)

### Features

* Upgrade to @parse/push-adapter 6.4.0 ([#9182](https://github.com/parse-community/parse-server/issues/9182)) ([ef1634b](https://github.com/parse-community/parse-server/commit/ef1634bf1f360429108d29b08032fc7961ff96a1))
2024-07-08 20:24:52 +00:00
Diamond Lewis ef1634bf1f feat: Upgrade to @parse/push-adapter 6.4.0 (#9182) 2024-07-08 22:23:57 +02:00
Diamond Lewis e7199e8d07 test: Investigate flaky tests by turning off tests randomizer (#9181) 2024-07-08 01:20:28 +02:00
Manuel 2ecc5a5bf5 test: Add test to return correct field values (#9179) 2024-07-07 19:10:53 +02:00
semantic-release-bot cd61c937f4 chore(release): 7.1.0-alpha.14 [skip ci]
# [7.1.0-alpha.14](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.13...7.1.0-alpha.14) (2024-07-07)

### Features

* Upgrade to Parse JS SDK 5.3.0 ([#9180](https://github.com/parse-community/parse-server/issues/9180)) ([dca187f](https://github.com/parse-community/parse-server/commit/dca187f91b93cbb362b22a3fb9ee38451799ff13))
2024-07-07 16:43:31 +00:00
Manuel dca187f91b feat: Upgrade to Parse JS SDK 5.3.0 (#9180) 2024-07-07 18:42:44 +02:00
semantic-release-bot 6bdd87c21a chore(release): 7.1.0-alpha.13 [skip ci]
# [7.1.0-alpha.13](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.12...7.1.0-alpha.13) (2024-07-01)

### Bug Fixes

* Invalid push notification tokens are not cleaned up from database for FCM API v2 ([#9173](https://github.com/parse-community/parse-server/issues/9173)) ([284da09](https://github.com/parse-community/parse-server/commit/284da09f4546356b37511a589fb5f64a3efffe79))
2024-07-01 19:38:23 +00:00
Manuel 284da09f45 fix: Invalid push notification tokens are not cleaned up from database for FCM API v2 (#9173) 2024-07-01 21:37:29 +02:00
semantic-release-bot 4906644d67 chore(release): 7.1.0 [skip ci]
# [7.1.0](https://github.com/parse-community/parse-server/compare/7.0.0...7.1.0) (2024-06-30)

### Bug Fixes

* `Parse.Cloud.startJob` and `Parse.Push.send` not returning status ID when setting Parse Server option `directAccess: true` ([#8766](https://github.com/parse-community/parse-server/issues/8766)) ([5b0efb2](https://github.com/parse-community/parse-server/commit/5b0efb22efe94c47f243cf8b1e6407ed5c5a67d3))
* `Required` option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations ([#8915](https://github.com/parse-community/parse-server/issues/8915)) ([907ad42](https://github.com/parse-community/parse-server/commit/907ad4267c228d26cfcefe7848b30ce85ba7ff8f))
* Facebook Limited Login not working due to incorrect domain in JWT validation ([#9122](https://github.com/parse-community/parse-server/issues/9122)) ([9d0bd2b](https://github.com/parse-community/parse-server/commit/9d0bd2badd6e5f7429d1af00b118225752e5d86a))
* Live query throws error when constraint `notEqualTo` is set to `null` ([#8835](https://github.com/parse-community/parse-server/issues/8835)) ([11d3e48](https://github.com/parse-community/parse-server/commit/11d3e484df862224c15d20f6171514948981ea90))
* Parse Server option `extendSessionOnUse` not working for session lengths < 24 hours ([#9113](https://github.com/parse-community/parse-server/issues/9113)) ([0a054e6](https://github.com/parse-community/parse-server/commit/0a054e6b541fd5ab470bf025665f5f7d2acedaa0))
* Rate limiting can fail when using Parse Server option `rateLimit.redisUrl` with clusters ([#8632](https://github.com/parse-community/parse-server/issues/8632)) ([c277739](https://github.com/parse-community/parse-server/commit/c27773962399f8e27691e3b8087e7e1d59516efd))
* SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) ([#9167](https://github.com/parse-community/parse-server/issues/9167)) ([2edf1e4](https://github.com/parse-community/parse-server/commit/2edf1e4c0363af01e97a7fbc97694f851b7d1ff3))

### Features

* Add `silent` log level for Cloud Code ([#8803](https://github.com/parse-community/parse-server/issues/8803)) ([5f81efb](https://github.com/parse-community/parse-server/commit/5f81efb42964c4c2fa8bcafee9446a0122e3ce21))
* Add server security check status `security.enableCheck` to Features Router ([#8679](https://github.com/parse-community/parse-server/issues/8679)) ([b07ec15](https://github.com/parse-community/parse-server/commit/b07ec153825882e97cc48dc84072c7f549f3238b))
* Prevent Parse Server start in case of unknown option in server configuration ([#8987](https://github.com/parse-community/parse-server/issues/8987)) ([8758e6a](https://github.com/parse-community/parse-server/commit/8758e6abb9dbb68757bddcbd332ad25100c24a0e))
* Upgrade to @parse/push-adapter 6.0.0 ([#9066](https://github.com/parse-community/parse-server/issues/9066)) ([18bdbf8](https://github.com/parse-community/parse-server/commit/18bdbf89c53a57648891ef582614ba7c2941e587))
* Upgrade to @parse/push-adapter 6.2.0 ([#9127](https://github.com/parse-community/parse-server/issues/9127)) ([ca20496](https://github.com/parse-community/parse-server/commit/ca20496f28e5ec1294a7a23c8559df82b79b2a04))
* Upgrade to Parse JS SDK 5.2.0 ([#9128](https://github.com/parse-community/parse-server/issues/9128)) ([665b8d5](https://github.com/parse-community/parse-server/commit/665b8d52d6cf5275179a5e1fb132c934edb53ecc))
2024-06-30 02:20:40 +00:00
Manuel 0633f98562 build: Release (#9170) 2024-06-30 04:19:45 +02:00
Manuel Trezza 31ad5d124e empty 2024-06-30 04:04:57 +02:00
semantic-release-bot 91dde99d3d chore(release): 7.1.0-beta.1 [skip ci]
# [7.1.0-beta.1](https://github.com/parse-community/parse-server/compare/7.0.0...7.1.0-beta.1) (2024-06-30)

### Bug Fixes

* `Parse.Cloud.startJob` and `Parse.Push.send` not returning status ID when setting Parse Server option `directAccess: true` ([#8766](https://github.com/parse-community/parse-server/issues/8766)) ([5b0efb2](https://github.com/parse-community/parse-server/commit/5b0efb22efe94c47f243cf8b1e6407ed5c5a67d3))
* `Required` option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations ([#8915](https://github.com/parse-community/parse-server/issues/8915)) ([907ad42](https://github.com/parse-community/parse-server/commit/907ad4267c228d26cfcefe7848b30ce85ba7ff8f))
* Facebook Limited Login not working due to incorrect domain in JWT validation ([#9122](https://github.com/parse-community/parse-server/issues/9122)) ([9d0bd2b](https://github.com/parse-community/parse-server/commit/9d0bd2badd6e5f7429d1af00b118225752e5d86a))
* Live query throws error when constraint `notEqualTo` is set to `null` ([#8835](https://github.com/parse-community/parse-server/issues/8835)) ([11d3e48](https://github.com/parse-community/parse-server/commit/11d3e484df862224c15d20f6171514948981ea90))
* Parse Server option `extendSessionOnUse` not working for session lengths < 24 hours ([#9113](https://github.com/parse-community/parse-server/issues/9113)) ([0a054e6](https://github.com/parse-community/parse-server/commit/0a054e6b541fd5ab470bf025665f5f7d2acedaa0))
* Rate limiting can fail when using Parse Server option `rateLimit.redisUrl` with clusters ([#8632](https://github.com/parse-community/parse-server/issues/8632)) ([c277739](https://github.com/parse-community/parse-server/commit/c27773962399f8e27691e3b8087e7e1d59516efd))
* SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) ([#9167](https://github.com/parse-community/parse-server/issues/9167)) ([2edf1e4](https://github.com/parse-community/parse-server/commit/2edf1e4c0363af01e97a7fbc97694f851b7d1ff3))

### Features

* Add `silent` log level for Cloud Code ([#8803](https://github.com/parse-community/parse-server/issues/8803)) ([5f81efb](https://github.com/parse-community/parse-server/commit/5f81efb42964c4c2fa8bcafee9446a0122e3ce21))
* Add server security check status `security.enableCheck` to Features Router ([#8679](https://github.com/parse-community/parse-server/issues/8679)) ([b07ec15](https://github.com/parse-community/parse-server/commit/b07ec153825882e97cc48dc84072c7f549f3238b))
* Prevent Parse Server start in case of unknown option in server configuration ([#8987](https://github.com/parse-community/parse-server/issues/8987)) ([8758e6a](https://github.com/parse-community/parse-server/commit/8758e6abb9dbb68757bddcbd332ad25100c24a0e))
* Upgrade to @parse/push-adapter 6.0.0 ([#9066](https://github.com/parse-community/parse-server/issues/9066)) ([18bdbf8](https://github.com/parse-community/parse-server/commit/18bdbf89c53a57648891ef582614ba7c2941e587))
* Upgrade to @parse/push-adapter 6.2.0 ([#9127](https://github.com/parse-community/parse-server/issues/9127)) ([ca20496](https://github.com/parse-community/parse-server/commit/ca20496f28e5ec1294a7a23c8559df82b79b2a04))
* Upgrade to Parse JS SDK 5.2.0 ([#9128](https://github.com/parse-community/parse-server/issues/9128)) ([665b8d5](https://github.com/parse-community/parse-server/commit/665b8d52d6cf5275179a5e1fb132c934edb53ecc))
2024-06-30 02:00:28 +00:00
Manuel b6452633a7 build: Release (#9169) 2024-06-30 03:56:49 +02:00
Manuel Trezza 4116f571a7 empty 2024-06-30 03:38:47 +02:00
semantic-release-bot 39e529d458 chore(release): 7.1.0-alpha.12 [skip ci]
# [7.1.0-alpha.12](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.11...7.1.0-alpha.12) (2024-06-30)

### Bug Fixes

* SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) ([#9167](https://github.com/parse-community/parse-server/issues/9167)) ([2edf1e4](https://github.com/parse-community/parse-server/commit/2edf1e4c0363af01e97a7fbc97694f851b7d1ff3))
2024-06-30 01:35:03 +00:00
Manuel 2edf1e4c03 fix: SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) (#9167) 2024-06-30 03:34:08 +02:00
semantic-release-bot ae72cf08bf chore(release): 7.1.0-alpha.11 [skip ci]
# [7.1.0-alpha.11](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.10...7.1.0-alpha.11) (2024-06-29)

### Features

* Upgrade to Parse JS SDK 5.2.0 ([#9128](https://github.com/parse-community/parse-server/issues/9128)) ([665b8d5](https://github.com/parse-community/parse-server/commit/665b8d52d6cf5275179a5e1fb132c934edb53ecc))
2024-06-29 18:00:43 +00:00
Manuel 665b8d52d6 feat: Upgrade to Parse JS SDK 5.2.0 (#9128) 2024-06-29 19:59:56 +02:00
dependabot[bot] 885aa12c8c refactor: Bump @babel/core from 7.24.3 to 7.24.7 (#9166) 2024-06-29 10:25:45 +02:00
dependabot[bot] c71deef865 refactor: Bump lru-cache from 10.1.0 to 10.2.2 (#9164) 2024-06-28 12:58:48 +02:00
dependabot[bot] cb73e2d94b refactor: Bump braces from 3.0.2 to 3.0.3 (#9152) 2024-06-26 10:22:49 +02:00
dependabot[bot] 5000c2ac3b refactor: Bump @grpc/grpc-js from 1.10.8 to 1.10.9 (#9150) 2024-06-24 22:28:12 +02:00
Corey 73eec3dfb1 docs: Fix codecov badge links (#9163) 2024-06-24 21:14:29 +02:00
Manuel 480282cf18 ci: Fix codecov token fail for Postgres (#9156) 2024-06-23 19:03:13 +02:00
Parse Platform e6be5117d0 refactor: Security upgrade node from lts-alpine to 20.14.0-alpine3.20 (#9160) 2024-06-23 19:01:31 +02:00
dependabot[bot] 5379135c88 refactor: Bump ws from 8.16.0 to 8.17.1 (#9159) 2024-06-23 19:01:09 +02:00
Manuel 42ff468960 test: Disable OAuth 1 tests with Twitter API (#9161) 2024-06-22 03:09:13 +02:00
semantic-release-bot 162c07b0a7 chore(release): 7.1.0-alpha.10 [skip ci]
# [7.1.0-alpha.10](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.9...7.1.0-alpha.10) (2024-06-11)

### Bug Fixes

* Live query throws error when constraint `notEqualTo` is set to `null` ([#8835](https://github.com/parse-community/parse-server/issues/8835)) ([11d3e48](https://github.com/parse-community/parse-server/commit/11d3e484df862224c15d20f6171514948981ea90))
2024-06-11 19:32:09 +00:00
Rahul Lanjewar 11d3e484df fix: Live query throws error when constraint notEqualTo is set to null (#8835) 2024-06-11 21:31:10 +02:00
Manuel 716925ec53 ci: Disable ci fail on codecov upload fail (#9151) 2024-06-11 12:19:54 +02:00
Corey 18f2002b84 refactor: Upgrade pg-promise from 11.5.5 to 11.7.8 (#9102) 2024-05-30 17:50:06 +02:00
Corey 61841859cc ci: Fix docker image fails build (#9141) 2024-05-30 17:40:10 +02:00
semantic-release-bot 61653a3983 chore(release): 7.1.0-alpha.9 [skip ci]
# [7.1.0-alpha.9](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.8...7.1.0-alpha.9) (2024-05-27)

### Bug Fixes

* Parse Server option `extendSessionOnUse` not working for session lengths < 24 hours ([#9113](https://github.com/parse-community/parse-server/issues/9113)) ([0a054e6](https://github.com/parse-community/parse-server/commit/0a054e6b541fd5ab470bf025665f5f7d2acedaa0))
2024-05-27 14:34:08 +00:00
Vivek Joshi 0a054e6b54 fix: Parse Server option extendSessionOnUse not working for session lengths < 24 hours (#9113) 2024-05-27 16:33:11 +02:00
semantic-release-bot d8ebdb3632 chore(release): 7.1.0-alpha.8 [skip ci]
# [7.1.0-alpha.8](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.7...7.1.0-alpha.8) (2024-05-16)

### Features

* Upgrade to @parse/push-adapter 6.2.0 ([#9127](https://github.com/parse-community/parse-server/issues/9127)) ([ca20496](https://github.com/parse-community/parse-server/commit/ca20496f28e5ec1294a7a23c8559df82b79b2a04))
2024-05-16 17:27:49 +00:00
Manuel ca20496f28 feat: Upgrade to @parse/push-adapter 6.2.0 (#9127) 2024-05-16 19:26:57 +02:00
semantic-release-bot b4739509f7 chore(release): 7.1.0-alpha.7 [skip ci]
# [7.1.0-alpha.7](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.6...7.1.0-alpha.7) (2024-05-16)

### Bug Fixes

* Facebook Limited Login not working due to incorrect domain in JWT validation ([#9122](https://github.com/parse-community/parse-server/issues/9122)) ([9d0bd2b](https://github.com/parse-community/parse-server/commit/9d0bd2badd6e5f7429d1af00b118225752e5d86a))
2024-05-16 11:55:36 +00:00
Chris 9d0bd2badd fix: Facebook Limited Login not working due to incorrect domain in JWT validation (#9122) 2024-05-16 13:54:41 +02:00
Doug Drechsel eba9dfff7b ci: Add test support for external database adapter (#8883) 2024-05-15 00:48:20 +02:00
semantic-release-bot 242002432f chore(release): 7.1.0-alpha.6 [skip ci]
# [7.1.0-alpha.6](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.5...7.1.0-alpha.6) (2024-04-14)

### Bug Fixes

* `Parse.Cloud.startJob` and `Parse.Push.send` not returning status ID when setting Parse Server option `directAccess: true` ([#8766](https://github.com/parse-community/parse-server/issues/8766)) ([5b0efb2](https://github.com/parse-community/parse-server/commit/5b0efb22efe94c47f243cf8b1e6407ed5c5a67d3))
2024-04-14 19:43:15 +00:00
Diamond Lewis 5b0efb22ef fix: Parse.Cloud.startJob and Parse.Push.send not returning status ID when setting Parse Server option directAccess: true (#8766) 2024-04-14 21:42:20 +02:00
Manuel 6364948d81 ci: Fix codecov upload (#9082) 2024-04-14 01:47:27 +02:00
dependabot[bot] e01c44a15b refactor: Bump @apollo/client from 3.9.5 to 3.9.11 (#9080) 2024-04-13 23:46:02 +02:00
Diamond Lewis bceb621a32 docs: Generate API documentation for release branch (#9081) 2024-04-13 22:36:29 +02:00
dependabot[bot] 2532acfce8 refactor: Bump graphql-relay from 0.10.0 to 0.10.1 (#9076) 2024-04-12 02:09:30 +02:00
semantic-release-bot 2c21aed890 chore(release): 7.1.0-alpha.5 [skip ci]
# [7.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.4...7.1.0-alpha.5) (2024-04-07)

### Features

* Prevent Parse Server start in case of unknown option in server configuration ([#8987](https://github.com/parse-community/parse-server/issues/8987)) ([8758e6a](https://github.com/parse-community/parse-server/commit/8758e6abb9dbb68757bddcbd332ad25100c24a0e))
2024-04-07 13:29:07 +00:00
Vivek Joshi 8758e6abb9 feat: Prevent Parse Server start in case of unknown option in server configuration (#8987) 2024-04-07 15:28:15 +02:00
Manuel f1469c6425 ci: Upgrade to latest MongoDB version in CI (#9070) 2024-04-06 22:29:22 +02:00
dependabot[bot] 855b5df758 refactor: Bump @parse/fs-files-adapter from 2.0.1 to 3.0.0 (#9073) 2024-04-06 02:34:55 +02:00
dependabot[bot] 480fc57984 refactor: Bump @babel/core from 7.24.0 to 7.24.3 (#9072) 2024-04-03 17:18:40 +02:00
dependabot[bot] 390bb92c15 refactor: Bump @node-rs/bcrypt from 1.1.0 to 1.10.1 (#9071) 2024-04-02 15:31:55 +02:00
dependabot[bot] 45d8ff9802 refactor: Bump clean-jsdoc-theme from 4.2.7 to 4.2.18 (#9068) 2024-04-01 19:41:09 +02:00
semantic-release-bot 9ac4fa70c9 chore(release): 7.1.0-alpha.4 [skip ci]
# [7.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.3...7.1.0-alpha.4) (2024-03-31)

### Features

* Upgrade to @parse/push-adapter 6.0.0 ([#9066](https://github.com/parse-community/parse-server/issues/9066)) ([18bdbf8](https://github.com/parse-community/parse-server/commit/18bdbf89c53a57648891ef582614ba7c2941e587))
2024-03-31 00:11:18 +00:00
Manuel 18bdbf89c5 feat: Upgrade to @parse/push-adapter 6.0.0 (#9066) 2024-03-31 01:10:28 +01:00
Manuel e31d230026 docs: Remove MongoDB rapid releases from support note (#9064) 2024-03-29 13:57:29 +01:00
Manuel 33c06b261e ci: Upgrade Node and MongoDB versions; fix CI check script for MongoDB versions (#9062) 2024-03-29 13:50:27 +01:00
dependabot[bot] d58d159fa2 refactor: Bump node-abort-controller from 3.0.1 to 3.1.1 (#9063) 2024-03-29 13:19:41 +01:00
dependabot[bot] 9f6da23511 refactor: Bump @actions/core from 1.9.1 to 1.10.1 (#9060) 2024-03-28 13:43:45 +01:00
dependabot[bot] a45d34691c refactor: Bump jsonwebtoken from 9.0.0 to 9.0.2 (#9055) 2024-03-28 01:01:31 +01:00
Parse Platform 3a087e7ad8 refactor: Security upgrade express from 4.18.3 to 4.19.2 (#9056) 2024-03-27 23:51:58 +01:00
Manuel 7959083760 refactor: simplify GitHub templates (#9053) 2024-03-25 16:20:08 +01:00
dependabot[bot] 06e54f1d37 refactor: Bump rate-limit-redis from 3.0.2 to 4.2.0 (#9051) 2024-03-25 12:54:22 +01:00
semantic-release-bot 4420835afa chore(release): 7.1.0-alpha.3 [skip ci]
# [7.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.2...7.1.0-alpha.3) (2024-03-24)

### Bug Fixes

* Rate limiting can fail when using Parse Server option `rateLimit.redisUrl` with clusters ([#8632](https://github.com/parse-community/parse-server/issues/8632)) ([c277739](https://github.com/parse-community/parse-server/commit/c27773962399f8e27691e3b8087e7e1d59516efd))
2024-03-24 01:18:11 +00:00
Daniel c277739623 fix: Rate limiting can fail when using Parse Server option rateLimit.redisUrl with clusters (#8632) 2024-03-24 02:17:21 +01:00
semantic-release-bot cfcb943ba5 chore(release): 7.1.0-alpha.2 [skip ci]
# [7.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/7.1.0-alpha.1...7.1.0-alpha.2) (2024-03-24)

### Features

* Add server security check status `security.enableCheck` to Features Router ([#8679](https://github.com/parse-community/parse-server/issues/8679)) ([b07ec15](https://github.com/parse-community/parse-server/commit/b07ec153825882e97cc48dc84072c7f549f3238b))
2024-03-24 00:51:31 +00:00
Daniel b07ec15382 feat: Add server security check status security.enableCheck to Features Router (#8679) 2024-03-24 01:50:38 +01:00
Parse Platform 79846f7c15 refactor: Upgrade express from 4.18.2 to 4.18.3 (#9046) 2024-03-23 16:16:28 +01:00
semantic-release-bot dc48be85f7 chore(release): 7.1.0-alpha.1 [skip ci]
# [7.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/7.0.0...7.1.0-alpha.1) (2024-03-23)

### Bug Fixes

* `Required` option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations ([#8915](https://github.com/parse-community/parse-server/issues/8915)) ([907ad42](https://github.com/parse-community/parse-server/commit/907ad4267c228d26cfcefe7848b30ce85ba7ff8f))

### Features

* Add `silent` log level for Cloud Code ([#8803](https://github.com/parse-community/parse-server/issues/8803)) ([5f81efb](https://github.com/parse-community/parse-server/commit/5f81efb42964c4c2fa8bcafee9446a0122e3ce21))
2024-03-23 00:52:58 +00:00
Manuel Trezza de54d1e9bc Merge release into alpha 2024-03-23 01:49:28 +01:00
dependabot[bot] e5b5c444b0 refactor: Bump pg-promise from 11.5.4 to 11.5.5 (#9040) 2024-03-22 15:14:40 +01:00
Manuel 1c0eced4bd ci: Fix CI version check (#9039) 2024-03-22 02:26:37 +01:00
semantic-release-bot 854ac9a017 chore(release): 7.0.0-alpha.31 [skip ci]
# [7.0.0-alpha.31](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.30...7.0.0-alpha.31) (2024-03-21)

### Features

* Add `silent` log level for Cloud Code ([#8803](https://github.com/parse-community/parse-server/issues/8803)) ([5f81efb](https://github.com/parse-community/parse-server/commit/5f81efb42964c4c2fa8bcafee9446a0122e3ce21))
2024-03-21 15:20:30 +00:00
Diamond Lewis 5f81efb429 feat: Add silent log level for Cloud Code (#8803) 2024-03-21 16:19:29 +01:00
semantic-release-bot 7d84b244ab chore(release): 7.0.0-alpha.30 [skip ci]
# [7.0.0-alpha.30](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.29...7.0.0-alpha.30) (2024-03-20)

### Bug Fixes

* `Required` option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations ([#8915](https://github.com/parse-community/parse-server/issues/8915)) ([907ad42](https://github.com/parse-community/parse-server/commit/907ad4267c228d26cfcefe7848b30ce85ba7ff8f))
2024-03-20 22:33:46 +00:00
Antoine Cormouls 907ad4267c fix: Required option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations (#8915) 2024-03-20 23:32:56 +01:00
dependabot[bot] 6fb19bd83a refactor: Bump mongodb-runner from 5.4.4 to 5.5.4 (#9036) 2024-03-20 19:53:51 +01:00
Parse Platform da368ea763 refactor: Upgrade @graphql-tools/merge from 8.4.1 to 9.0.3 (#9030) 2024-03-20 06:26:28 +01:00
Antoine Cormouls 6d4663b47e refactor: Dry handleAuthData for safer code maintenance in the future (#9025) 2024-03-19 22:41:21 +01:00
Manuel 1a2b513e8c ci: Add lint rule for curly braces (#9032) 2024-03-19 22:32:27 +01:00
semantic-release-bot c83de8c4ea chore(release): 7.0.0 [skip ci]
# [7.0.0](https://github.com/parse-community/parse-server/compare/6.4.0...7.0.0) (2024-03-19)

### Bug Fixes

* CacheAdapter does not connect when using a CacheAdapter with a JSON config ([#8633](https://github.com/parse-community/parse-server/issues/8633)) ([720d24e](https://github.com/parse-community/parse-server/commit/720d24e18540da35d50957f17be878316ec30318))
* Conditional email verification not working in some cases if `verifyUserEmails`, `preventLoginWithUnverifiedEmail` set to functions ([#8838](https://github.com/parse-community/parse-server/issues/8838)) ([8e7a6b1](https://github.com/parse-community/parse-server/commit/8e7a6b1480c0117e6c73e7adc5a6619115a04e85))
* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3))
* Deny request if master key is not set in Parse Server option `masterKeyIps` regardless of ACL and CLP ([#8957](https://github.com/parse-community/parse-server/issues/8957)) ([a7b5b38](https://github.com/parse-community/parse-server/commit/a7b5b38418cbed9be3f4a7665f25b97f592663e1))
* Docker image not published to Docker Hub on new release ([#8905](https://github.com/parse-community/parse-server/issues/8905)) ([a2ac8d1](https://github.com/parse-community/parse-server/commit/a2ac8d133c71cd7b61e5ef59c4be915cfea85db6))
* Docker version releases by removing arm/v6 and arm/v7 support ([#8976](https://github.com/parse-community/parse-server/issues/8976)) ([1f62dd0](https://github.com/parse-community/parse-server/commit/1f62dd0f4e107b22a387692558a042ee26ce8703))
* GraphQL file upload fails in case of use of pointer or relation ([#8721](https://github.com/parse-community/parse-server/issues/8721)) ([1aba638](https://github.com/parse-community/parse-server/commit/1aba6382c873fb489d4a898d301e6da9fb6aa61b))
* Improve PostgreSQL injection detection; fixes security vulnerability [GHSA-6927-3vr9-fxf2](https://github.com/parse-community/parse-server/security/advisories/GHSA-6927-3vr9-fxf2) which affects Parse Server deployments using a Postgres database ([#8961](https://github.com/parse-community/parse-server/issues/8961)) ([cbefe77](https://github.com/parse-community/parse-server/commit/cbefe770a7260b54748a058b8a7389937dc35833))
* Incomplete user object in `verifyEmail` function if both username and email are changed ([#8889](https://github.com/parse-community/parse-server/issues/8889)) ([1eb95ae](https://github.com/parse-community/parse-server/commit/1eb95aeb41a96250e582d79a703f6adcb403c08b))
* Parse Server option `emailVerifyTokenReuseIfValid: true` generates new token on every email verification request ([#8885](https://github.com/parse-community/parse-server/issues/8885)) ([0023ce4](https://github.com/parse-community/parse-server/commit/0023ce448a5e9423337d0e1a25648bde1156bc95))
* Parse Server option `fileExtensions` default value rejects file extensions that are less than 3 or more than 4 characters long ([#8699](https://github.com/parse-community/parse-server/issues/8699)) ([2760381](https://github.com/parse-community/parse-server/commit/276038118377c2b22381bcd8d30337203822121b))
* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a))
* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c))
* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1))
* Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) ([#9024](https://github.com/parse-community/parse-server/issues/9024)) ([9f6e342](https://github.com/parse-community/parse-server/commit/9f6e3429d3b326cf4e2994733c618d08032fac6e))
* Server crashes when receiving an array of `Parse.Pointer` in the request body ([#8784](https://github.com/parse-community/parse-server/issues/8784)) ([66e3603](https://github.com/parse-community/parse-server/commit/66e36039d8af654cfa0284666c0ddd94975dcb52))
* Username is `undefined` in email verification link on email change ([#8887](https://github.com/parse-community/parse-server/issues/8887)) ([e315c13](https://github.com/parse-community/parse-server/commit/e315c137bf41bedfa8f0df537f2c3f6ab45b7e60))

### Features

* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29))
* Add `installationId` to arguments for `verifyUserEmails`, `preventLoginWithUnverifiedEmail` ([#8836](https://github.com/parse-community/parse-server/issues/8836)) ([a22dbe1](https://github.com/parse-community/parse-server/commit/a22dbe16d5ac0090608f6caaf0ebd134925b7fd4))
* Add `installationId`, `ip`, `resendRequest` to arguments passed to `verifyUserEmails` on verification email request ([#8873](https://github.com/parse-community/parse-server/issues/8873)) ([8adcbee](https://github.com/parse-community/parse-server/commit/8adcbee11283d3e95179ca2047e2615f52c18806))
* Add `Parse.User` as function parameter to Parse Server options `verifyUserEmails`, `preventLoginWithUnverifiedEmail` on login ([#8850](https://github.com/parse-community/parse-server/issues/8850)) ([972f630](https://github.com/parse-community/parse-server/commit/972f6300163b3cd7d95eeb95986e8322c95f821c))
* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620))
* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d))
* Add password validation via POST request for user with unverified email using master key and option `ignoreEmailVerification` ([#8895](https://github.com/parse-community/parse-server/issues/8895)) ([633a9d2](https://github.com/parse-community/parse-server/commit/633a9d25e4253e2125bc93c02ee8a37e0f5f7b83))
* Add support for MongoDB 7 ([#8761](https://github.com/parse-community/parse-server/issues/8761)) ([3de8494](https://github.com/parse-community/parse-server/commit/3de8494a221991dfd10a74e0a2dc89576265c9b7))
* Add support for MongoDB query comment ([#8928](https://github.com/parse-community/parse-server/issues/8928)) ([2170962](https://github.com/parse-community/parse-server/commit/2170962a50fa353ed85eda3f11dce7ee3647b087))
* Add support for Node 20, drop support for Node 14, 16 ([#8907](https://github.com/parse-community/parse-server/issues/8907)) ([ced4872](https://github.com/parse-community/parse-server/commit/ced487246ea0ef72a8aa014991f003209b34841e))
* Add support for Postgres 16 ([#8898](https://github.com/parse-community/parse-server/issues/8898)) ([99489b2](https://github.com/parse-community/parse-server/commit/99489b22e4f0982e6cb39992974b51aa8d3a31e4))
* Allow `Parse.Session.current` on expired session token instead of throwing error ([#8722](https://github.com/parse-community/parse-server/issues/8722)) ([f9dde4a](https://github.com/parse-community/parse-server/commit/f9dde4a9f8a90c63f71172c9bc515b0f6c6d2e4a))
* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d))
* Deprecation DEPPS5: Config option `allowClientClassCreation` defaults to `false` ([#8849](https://github.com/parse-community/parse-server/issues/8849)) ([29624e0](https://github.com/parse-community/parse-server/commit/29624e0fae17161cd412ae58d35a195cfa286cad))
* Deprecation DEPPS6: Authentication adapters disabled by default ([#8858](https://github.com/parse-community/parse-server/issues/8858)) ([0cf58eb](https://github.com/parse-community/parse-server/commit/0cf58eb8d60c8e5f485764e154f3214c49eee430))
* Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax ([#8855](https://github.com/parse-community/parse-server/issues/8855)) ([4e6a375](https://github.com/parse-community/parse-server/commit/4e6a375b5184ae0f7aa256a921eca4021c609435))
* Deprecation DEPPS8:  Parse Server option `allowExpiredAuthDataToken` defaults to `false` ([#8860](https://github.com/parse-community/parse-server/issues/8860)) ([e29845f](https://github.com/parse-community/parse-server/commit/e29845f8dacac09ce3093d75c0d92330c24389e8))
* Deprecation DEPPS9: LiveQuery `fields` option is renamed to `keys` ([#8852](https://github.com/parse-community/parse-server/issues/8852)) ([38983e8](https://github.com/parse-community/parse-server/commit/38983e8e9b5cdbd006f311a2338103624137d013))
* Node process exits with error code 1 on uncaught exception to allow custom uncaught exception handling ([#8894](https://github.com/parse-community/parse-server/issues/8894)) ([70c280c](https://github.com/parse-community/parse-server/commit/70c280ca578ff28b5acf92f37fbe06d42a5b34ca))
* Switch GraphQL server from Yoga v2 to Apollo v4 ([#8959](https://github.com/parse-community/parse-server/issues/8959)) ([105ae7c](https://github.com/parse-community/parse-server/commit/105ae7c8a57d5a650b243174a80c26bf6db16e28))
* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740))
* Upgrade to Parse JS SDK 5 ([#9022](https://github.com/parse-community/parse-server/issues/9022)) ([ad4aa83](https://github.com/parse-community/parse-server/commit/ad4aa83983205a0e27639f6ee6a4a5963b67e4b8))

### Performance Improvements

* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522))

### BREAKING CHANGES

* The Parse Server option `allowClientClassCreation` defaults to `false`. ([29624e0](29624e0))
* A request using the master key will now be rejected as unauthorized if the IP from which the request originates is not set in the Parse Server option `masterKeyIps`, even if the request does not require the master key permission, for example for a public object in a public class class. ([a7b5b38](a7b5b38))
* Node process now exits with code 1 on uncaught exceptions, enabling custom handlers that were blocked by Parse Server's default behavior of re-throwing errors. This change may lead to automatic process restarts by the environment, unlike before. ([70c280c](70c280c))
* Authentication adapters are disabled by default; to use an authentication adapter it needs to be explicitly enabled in the Parse Server authentication adapter option `auth.<provider>.enabled: true` ([0cf58eb](0cf58eb))
* Parse Server option `allowExpiredAuthDataToken` defaults to `false`; a 3rd party authentication token will be validated every time the user tries to log in and the login will fail if the token has expired; the effect of this change may differ for different authentication adapters, depending on the token lifetime and the token refresh logic of the adapter ([e29845f](e29845f))
* LiveQuery `fields` option is renamed to `keys` ([38983e8](38983e8))
* Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'` ([4e6a375](4e6a375))
* Removes support for Node 14 and 16 ([ced4872](ced4872))
* Removes support for Postgres 11 and 12 ([99489b2](99489b2))
* The `Parse.User` passed as argument if `verifyUserEmails` is set to a function is renamed from `user` to `object` for consistency with invocations of `verifyUserEmails` on signup or login; the user object is not a plain JavaScript object anymore but an instance of `Parse.User` ([8adcbee](8adcbee))
* `Parse.Session.current()` no longer throws an error if the session token is expired, but instead returns the session token with its expiration date to allow checking its validity ([f9dde4a](f9dde4a))
* `Parse.Query` no longer supports the BSON type `code`; although this feature was never officially documented, its removal is announced as a breaking change to protect deployments where it might be in use. ([3de8494](3de8494))
2024-03-19 20:41:55 +00:00
Manuel 4c74b2b926 build: Release (#9034) 2024-03-19 21:41:07 +01:00
Manuel Trezza 60cf2dd054 empty 2024-03-19 19:47:18 +01:00
semantic-release-bot 0d5acf3d9b chore(release): 7.0.0-beta.1 [skip ci]
# [7.0.0-beta.1](https://github.com/parse-community/parse-server/compare/6.5.0-beta.1...7.0.0-beta.1) (2024-03-19)

### Bug Fixes

* CacheAdapter does not connect when using a CacheAdapter with a JSON config ([#8633](https://github.com/parse-community/parse-server/issues/8633)) ([720d24e](https://github.com/parse-community/parse-server/commit/720d24e18540da35d50957f17be878316ec30318))
* Conditional email verification not working in some cases if `verifyUserEmails`, `preventLoginWithUnverifiedEmail` set to functions ([#8838](https://github.com/parse-community/parse-server/issues/8838)) ([8e7a6b1](https://github.com/parse-community/parse-server/commit/8e7a6b1480c0117e6c73e7adc5a6619115a04e85))
* Deny request if master key is not set in Parse Server option `masterKeyIps` regardless of ACL and CLP ([#8957](https://github.com/parse-community/parse-server/issues/8957)) ([a7b5b38](https://github.com/parse-community/parse-server/commit/a7b5b38418cbed9be3f4a7665f25b97f592663e1))
* Docker image not published to Docker Hub on new release ([#8905](https://github.com/parse-community/parse-server/issues/8905)) ([a2ac8d1](https://github.com/parse-community/parse-server/commit/a2ac8d133c71cd7b61e5ef59c4be915cfea85db6))
* Docker version releases by removing arm/v6 and arm/v7 support ([#8976](https://github.com/parse-community/parse-server/issues/8976)) ([1f62dd0](https://github.com/parse-community/parse-server/commit/1f62dd0f4e107b22a387692558a042ee26ce8703))
* GraphQL file upload fails in case of use of pointer or relation ([#8721](https://github.com/parse-community/parse-server/issues/8721)) ([1aba638](https://github.com/parse-community/parse-server/commit/1aba6382c873fb489d4a898d301e6da9fb6aa61b))
* Improve PostgreSQL injection detection; fixes security vulnerability [GHSA-6927-3vr9-fxf2](https://github.com/parse-community/parse-server/security/advisories/GHSA-6927-3vr9-fxf2) which affects Parse Server deployments using a Postgres database ([#8961](https://github.com/parse-community/parse-server/issues/8961)) ([cbefe77](https://github.com/parse-community/parse-server/commit/cbefe770a7260b54748a058b8a7389937dc35833))
* Incomplete user object in `verifyEmail` function if both username and email are changed ([#8889](https://github.com/parse-community/parse-server/issues/8889)) ([1eb95ae](https://github.com/parse-community/parse-server/commit/1eb95aeb41a96250e582d79a703f6adcb403c08b))
* Parse Server option `emailVerifyTokenReuseIfValid: true` generates new token on every email verification request ([#8885](https://github.com/parse-community/parse-server/issues/8885)) ([0023ce4](https://github.com/parse-community/parse-server/commit/0023ce448a5e9423337d0e1a25648bde1156bc95))
* Parse Server option `fileExtensions` default value rejects file extensions that are less than 3 or more than 4 characters long ([#8699](https://github.com/parse-community/parse-server/issues/8699)) ([2760381](https://github.com/parse-community/parse-server/commit/276038118377c2b22381bcd8d30337203822121b))
* Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) ([#9024](https://github.com/parse-community/parse-server/issues/9024)) ([9f6e342](https://github.com/parse-community/parse-server/commit/9f6e3429d3b326cf4e2994733c618d08032fac6e))
* Server crashes when receiving an array of `Parse.Pointer` in the request body ([#8784](https://github.com/parse-community/parse-server/issues/8784)) ([66e3603](https://github.com/parse-community/parse-server/commit/66e36039d8af654cfa0284666c0ddd94975dcb52))
* Username is `undefined` in email verification link on email change ([#8887](https://github.com/parse-community/parse-server/issues/8887)) ([e315c13](https://github.com/parse-community/parse-server/commit/e315c137bf41bedfa8f0df537f2c3f6ab45b7e60))

### Features

* Add `installationId` to arguments for `verifyUserEmails`, `preventLoginWithUnverifiedEmail` ([#8836](https://github.com/parse-community/parse-server/issues/8836)) ([a22dbe1](https://github.com/parse-community/parse-server/commit/a22dbe16d5ac0090608f6caaf0ebd134925b7fd4))
* Add `installationId`, `ip`, `resendRequest` to arguments passed to `verifyUserEmails` on verification email request ([#8873](https://github.com/parse-community/parse-server/issues/8873)) ([8adcbee](https://github.com/parse-community/parse-server/commit/8adcbee11283d3e95179ca2047e2615f52c18806))
* Add `Parse.User` as function parameter to Parse Server options `verifyUserEmails`, `preventLoginWithUnverifiedEmail` on login ([#8850](https://github.com/parse-community/parse-server/issues/8850)) ([972f630](https://github.com/parse-community/parse-server/commit/972f6300163b3cd7d95eeb95986e8322c95f821c))
* Add password validation via POST request for user with unverified email using master key and option `ignoreEmailVerification` ([#8895](https://github.com/parse-community/parse-server/issues/8895)) ([633a9d2](https://github.com/parse-community/parse-server/commit/633a9d25e4253e2125bc93c02ee8a37e0f5f7b83))
* Add support for MongoDB 7 ([#8761](https://github.com/parse-community/parse-server/issues/8761)) ([3de8494](https://github.com/parse-community/parse-server/commit/3de8494a221991dfd10a74e0a2dc89576265c9b7))
* Add support for MongoDB query comment ([#8928](https://github.com/parse-community/parse-server/issues/8928)) ([2170962](https://github.com/parse-community/parse-server/commit/2170962a50fa353ed85eda3f11dce7ee3647b087))
* Add support for Node 20, drop support for Node 14, 16 ([#8907](https://github.com/parse-community/parse-server/issues/8907)) ([ced4872](https://github.com/parse-community/parse-server/commit/ced487246ea0ef72a8aa014991f003209b34841e))
* Add support for Postgres 16 ([#8898](https://github.com/parse-community/parse-server/issues/8898)) ([99489b2](https://github.com/parse-community/parse-server/commit/99489b22e4f0982e6cb39992974b51aa8d3a31e4))
* Allow `Parse.Session.current` on expired session token instead of throwing error ([#8722](https://github.com/parse-community/parse-server/issues/8722)) ([f9dde4a](https://github.com/parse-community/parse-server/commit/f9dde4a9f8a90c63f71172c9bc515b0f6c6d2e4a))
* Deprecation DEPPS5: Config option `allowClientClassCreation` defaults to `false` ([#8849](https://github.com/parse-community/parse-server/issues/8849)) ([29624e0](https://github.com/parse-community/parse-server/commit/29624e0fae17161cd412ae58d35a195cfa286cad))
* Deprecation DEPPS6: Authentication adapters disabled by default ([#8858](https://github.com/parse-community/parse-server/issues/8858)) ([0cf58eb](https://github.com/parse-community/parse-server/commit/0cf58eb8d60c8e5f485764e154f3214c49eee430))
* Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax ([#8855](https://github.com/parse-community/parse-server/issues/8855)) ([4e6a375](https://github.com/parse-community/parse-server/commit/4e6a375b5184ae0f7aa256a921eca4021c609435))
* Deprecation DEPPS8:  Parse Server option `allowExpiredAuthDataToken` defaults to `false` ([#8860](https://github.com/parse-community/parse-server/issues/8860)) ([e29845f](https://github.com/parse-community/parse-server/commit/e29845f8dacac09ce3093d75c0d92330c24389e8))
* Deprecation DEPPS9: LiveQuery `fields` option is renamed to `keys` ([#8852](https://github.com/parse-community/parse-server/issues/8852)) ([38983e8](https://github.com/parse-community/parse-server/commit/38983e8e9b5cdbd006f311a2338103624137d013))
* Node process exits with error code 1 on uncaught exception to allow custom uncaught exception handling ([#8894](https://github.com/parse-community/parse-server/issues/8894)) ([70c280c](https://github.com/parse-community/parse-server/commit/70c280ca578ff28b5acf92f37fbe06d42a5b34ca))
* Switch GraphQL server from Yoga v2 to Apollo v4 ([#8959](https://github.com/parse-community/parse-server/issues/8959)) ([105ae7c](https://github.com/parse-community/parse-server/commit/105ae7c8a57d5a650b243174a80c26bf6db16e28))
* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740))
* Upgrade to Parse JS SDK 5 ([#9022](https://github.com/parse-community/parse-server/issues/9022)) ([ad4aa83](https://github.com/parse-community/parse-server/commit/ad4aa83983205a0e27639f6ee6a4a5963b67e4b8))

### Performance Improvements

* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522))

### BREAKING CHANGES

* The Parse Server option `allowClientClassCreation` defaults to `false`. ([29624e0](29624e0))
* A request using the master key will now be rejected as unauthorized if the IP from which the request originates is not set in the Parse Server option `masterKeyIps`, even if the request does not require the master key permission, for example for a public object in a public class class. ([a7b5b38](a7b5b38))
* Node process now exits with code 1 on uncaught exceptions, enabling custom handlers that were blocked by Parse Server's default behavior of re-throwing errors. This change may lead to automatic process restarts by the environment, unlike before. ([70c280c](70c280c))
* Authentication adapters are disabled by default; to use an authentication adapter it needs to be explicitly enabled in the Parse Server authentication adapter option `auth.<provider>.enabled: true` ([0cf58eb](0cf58eb))
* Parse Server option `allowExpiredAuthDataToken` defaults to `false`; a 3rd party authentication token will be validated every time the user tries to log in and the login will fail if the token has expired; the effect of this change may differ for different authentication adapters, depending on the token lifetime and the token refresh logic of the adapter ([e29845f](e29845f))
* LiveQuery `fields` option is renamed to `keys` ([38983e8](38983e8))
* Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'` ([4e6a375](4e6a375))
* Removes support for Node 14 and 16 ([ced4872](ced4872))
* Removes support for Postgres 11 and 12 ([99489b2](99489b2))
* The `Parse.User` passed as argument if `verifyUserEmails` is set to a function is renamed from `user` to `object` for consistency with invocations of `verifyUserEmails` on signup or login; the user object is not a plain JavaScript object anymore but an instance of `Parse.User` ([8adcbee](8adcbee))
* `Parse.Session.current()` no longer throws an error if the session token is expired, but instead returns the session token with its expiration date to allow checking its validity ([f9dde4a](f9dde4a))
* `Parse.Query` no longer supports the BSON type `code`; although this feature was never officially documented, its removal is announced as a breaking change to protect deployments where it might be in use. ([3de8494](3de8494))
2024-03-19 18:25:49 +00:00
Manuel 5c2c120021 build: Release beta (#9033) 2024-03-19 19:24:59 +01:00
Manuel Trezza 63d4880ebf empty 2024-03-19 18:47:57 +01:00
semantic-release-bot 09310a7700 chore(release): 7.0.0-alpha.29 [skip ci]
# [7.0.0-alpha.29](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.28...7.0.0-alpha.29) (2024-03-19)

### Bug Fixes

* Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) ([#9024](https://github.com/parse-community/parse-server/issues/9024)) ([9f6e342](https://github.com/parse-community/parse-server/commit/9f6e3429d3b326cf4e2994733c618d08032fac6e))
2024-03-19 16:42:50 +00:00
Manuel 9f6e3429d3 fix: Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) (#9024) 2024-03-19 17:42:00 +01:00
semantic-release-bot 901aaf8cd3 chore(release): 7.0.0-alpha.28 [skip ci]
# [7.0.0-alpha.28](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.27...7.0.0-alpha.28) (2024-03-17)

### Features

* Upgrade to Parse JS SDK 5 ([#9022](https://github.com/parse-community/parse-server/issues/9022)) ([ad4aa83](https://github.com/parse-community/parse-server/commit/ad4aa83983205a0e27639f6ee6a4a5963b67e4b8))
2024-03-17 03:09:34 +00:00
Daniel ad4aa83983 feat: Upgrade to Parse JS SDK 5 (#9022) 2024-03-17 04:08:52 +01:00
Parse Platform 1c2bb7ca28 refactor: Security upgrade follow-redirects from 1.15.5 to 1.15.6 (#9017) 2024-03-16 10:09:28 +01:00
Oussama Meglali ba098970df test: Fix flaky tests for comment in MongoDB query (#9015) 2024-03-15 22:53:25 +01:00
semantic-release-bot 1ffc48fd08 chore(release): 7.0.0-alpha.27 [skip ci]
# [7.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.26...7.0.0-alpha.27) (2024-03-15)

### Bug Fixes

* CacheAdapter does not connect when using a CacheAdapter with a JSON config ([#8633](https://github.com/parse-community/parse-server/issues/8633)) ([720d24e](https://github.com/parse-community/parse-server/commit/720d24e18540da35d50957f17be878316ec30318))
2024-03-15 16:46:57 +00:00
Daniel 720d24e185 fix: CacheAdapter does not connect when using a CacheAdapter with a JSON config (#8633) 2024-03-15 17:46:06 +01:00
dependabot[bot] 2065897dc6 refactor: Bump jsdoc from 3.6.3 to 4.0.2 (#9014) 2024-03-14 18:07:34 +01:00
dependabot[bot] 37e3934a85 refactor: Bump express-rate-limit from 6.7.0 to 6.11.2 (#9007) 2024-03-13 17:45:47 +01:00
dependabot[bot] 6f20e54cce refactor: Bump @babel/cli from 7.10.0 to 7.23.9 (#9004) 2024-03-12 13:12:30 +01:00
dependabot[bot] a5050df7fe refactor: Bump winston from 3.11.0 to 3.12.0 (#9002) 2024-03-11 21:46:41 +01:00
dependabot[bot] 90e103528d refactor: Bump @apollo/server from 4.10.0 to 4.10.1 (#9000) 2024-03-11 19:45:19 +01:00
semantic-release-bot c7b2068329 chore(release): 7.0.0-alpha.26 [skip ci]
# [7.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.25...7.0.0-alpha.26) (2024-03-10)

### Bug Fixes

* Parse Server option `fileExtensions` default value rejects file extensions that are less than 3 or more than 4 characters long ([#8699](https://github.com/parse-community/parse-server/issues/8699)) ([2760381](https://github.com/parse-community/parse-server/commit/276038118377c2b22381bcd8d30337203822121b))
2024-03-10 14:12:11 +00:00
Daniel 2760381183 fix: Parse Server option fileExtensions default value rejects file extensions that are less than 3 or more than 4 characters long (#8699) 2024-03-10 15:11:27 +01:00
dependabot[bot] 3fbd926b80 refactor: Bump husky from 4.3.8 to 9.0.11 (#8996) 2024-03-09 17:28:11 +01:00
dependabot[bot] 41f009db4e refactor: Bump @babel/plugin-transform-flow-strip-types from 7.9.0 to 7.23.3 (#8994) 2024-03-09 15:52:57 +01:00
dependabot[bot] fbf6d41a00 refactor: Bump jose from 4.15.4 to 4.15.5 (#8998) 2024-03-09 14:42:25 +01:00
dependabot[bot] a56fb76433 refactor: Bump semver from 7.5.4 to 7.6.0 (#8995) 2024-03-08 18:16:01 +01:00
dependabot[bot] 98edbdbd4b refactor: Bump @babel/preset-env from 7.10.0 to 7.24.0 (#8993) 2024-03-08 01:51:30 +01:00
dependabot[bot] 3de9acc006 refactor: Bump form-data from 3.0.0 to 4.0.0 (#8983) 2024-03-06 15:16:33 +01:00
dependabot[bot] cf99570c75 refactor: Bump @babel/core from 7.20.2 to 7.24.0 (#8992) 2024-03-06 14:43:07 +01:00
dependabot[bot] 21458ff502 refactor: Bump @apollo/client from 3.6.1 to 3.9.5 (#8990) 2024-03-06 14:25:20 +01:00
Parse Platform 7773d3b5ef refactor: Upgrade graphql-list-fields from 2.0.2 to 2.0.4 (#8980) 2024-03-06 13:55:30 +01:00
Parse Platform d3f0886707 refactor: Upgrade @apollo/server from 4.9.3 to 4.10.0 (#8978) 2024-03-06 11:37:04 +01:00
dependabot[bot] 2988c450e1 refactor: Bump @graphql-tools/schema from 9.0.4 to 10.0.3 (#8984) 2024-03-06 11:00:53 +01:00
dependabot[bot] 042d69614e refactor: Upgrade @parse/push-adapter from 5.0.2 to 5.1.1 (#8986) 2024-03-06 10:14:42 +01:00
semantic-release-bot edd416b647 chore(release): 7.0.0-alpha.25 [skip ci]
# [7.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.24...7.0.0-alpha.25) (2024-03-05)

### Features

* Deprecation DEPPS5: Config option `allowClientClassCreation` defaults to `false` ([#8849](https://github.com/parse-community/parse-server/issues/8849)) ([29624e0](https://github.com/parse-community/parse-server/commit/29624e0fae17161cd412ae58d35a195cfa286cad))

### BREAKING CHANGES

* The Parse Server option `allowClientClassCreation` defaults to `false`. ([29624e0](29624e0))
2024-03-05 19:08:50 +00:00
Onur 29624e0fae feat: Deprecation DEPPS5: Config option allowClientClassCreation defaults to false (#8849)
BREAKING CHANGE: The Parse Server option `allowClientClassCreation` defaults to `false`.
2024-03-05 20:05:54 +01:00
semantic-release-bot fe1e4d9775 chore(release): 7.0.0-alpha.24 [skip ci]
# [7.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.23...7.0.0-alpha.24) (2024-03-05)

### Bug Fixes

* Docker version releases by removing arm/v6 and arm/v7 support ([#8976](https://github.com/parse-community/parse-server/issues/8976)) ([1f62dd0](https://github.com/parse-community/parse-server/commit/1f62dd0f4e107b22a387692558a042ee26ce8703))
2024-03-05 07:55:28 +00:00
Corey 1f62dd0f4e fix: Docker version releases by removing arm/v6 and arm/v7 support (#8976) 2024-03-05 08:54:42 +01:00
semantic-release-bot f9c39edcbc chore(release): 7.0.0-alpha.23 [skip ci]
# [7.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.22...7.0.0-alpha.23) (2024-03-03)

### Features

* Add support for MongoDB query comment ([#8928](https://github.com/parse-community/parse-server/issues/8928)) ([2170962](https://github.com/parse-community/parse-server/commit/2170962a50fa353ed85eda3f11dce7ee3647b087))
2024-03-03 01:28:51 +00:00
Oussama Meglali 2170962a50 feat: Add support for MongoDB query comment (#8928) 2024-03-03 02:27:57 +01:00
dependabot[bot] afcafdba1e refactor: Bump winston-daily-rotate-file from 4.7.1 to 5.0.0 (#8970) 2024-03-02 17:10:19 +01:00
dependabot[bot] a84ecc9fec refactor: Bump commander from 10.0.1 to 12.0.0 (#8969) 2024-03-02 16:51:18 +01:00
dependabot[bot] 9d3030f6a8 refactor: Bump madge from 5.0.1 to 6.1.0 (#8971) 2024-03-02 16:29:36 +01:00
dependabot[bot] dfea561f44 refactor: Upgrade ansi-regex from 3.0.0 to 5.0.1 (#8967) 2024-03-02 15:36:32 +01:00
Manuel 0613174b34 ci: Add dependabot config to use proper commit prefix in PR title (#8968) 2024-03-02 14:56:21 +01:00
Parse Platform dbe8b72d8a refactor: Security upgrade @apollo/server from 4.9.2 to 4.9.3 (#8964) 2024-03-02 14:38:26 +01:00
semantic-release-bot 9293ce8ca5 chore(release): 7.0.0-alpha.22 [skip ci]
# [7.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.21...7.0.0-alpha.22) (2024-03-02)

### Features

* Switch GraphQL server from Yoga v2 to Apollo v4 ([#8959](https://github.com/parse-community/parse-server/issues/8959)) ([105ae7c](https://github.com/parse-community/parse-server/commit/105ae7c8a57d5a650b243174a80c26bf6db16e28))
2024-03-02 01:07:38 +00:00
Onur 105ae7c8a5 feat: Switch GraphQL server from Yoga v2 to Apollo v4 (#8959) 2024-03-02 02:06:47 +01:00
semantic-release-bot 01c97f7ab7 chore(release): 7.0.0-alpha.21 [skip ci]
# [7.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.20...7.0.0-alpha.21) (2024-03-01)

### Bug Fixes

* Deny request if master key is not set in Parse Server option `masterKeyIps` regardless of ACL and CLP ([#8957](https://github.com/parse-community/parse-server/issues/8957)) ([a7b5b38](https://github.com/parse-community/parse-server/commit/a7b5b38418cbed9be3f4a7665f25b97f592663e1))

### BREAKING CHANGES

* A request using the master key will now be rejected as unauthorized if the IP from which the request originates is not set in the Parse Server option `masterKeyIps`, even if the request does not require the master key permission, for example for a public object in a public class class. ([a7b5b38](a7b5b38))
2024-03-01 17:37:52 +00:00
EhsanParsania a7b5b38418 fix: Deny request if master key is not set in Parse Server option masterKeyIps regardless of ACL and CLP (#8957)
BREAKING CHANGE: A request using the master key will now be rejected as unauthorized if the IP from which the request originates is not set in the Parse Server option `masterKeyIps`, even if the request does not require the master key permission, for example for a public object in a public class class.
2024-03-01 18:37:07 +01:00
semantic-release-bot 5452c8f41f chore(release): 7.0.0-alpha.20 [skip ci]
# [7.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.19...7.0.0-alpha.20) (2024-03-01)

### Bug Fixes

* Improve PostgreSQL injection detection; fixes security vulnerability [GHSA-6927-3vr9-fxf2](https://github.com/parse-community/parse-server/security/advisories/GHSA-6927-3vr9-fxf2) which affects Parse Server deployments using a Postgres database ([#8961](https://github.com/parse-community/parse-server/issues/8961)) ([cbefe77](https://github.com/parse-community/parse-server/commit/cbefe770a7260b54748a058b8a7389937dc35833))
2024-03-01 15:53:21 +00:00
Manuel cbefe770a7 fix: Improve PostgreSQL injection detection; fixes security vulnerability [GHSA-6927-3vr9-fxf2](https://github.com/parse-community/parse-server/security/advisories/GHSA-6927-3vr9-fxf2) which affects Parse Server deployments using a Postgres database (#8961) 2024-03-01 16:52:05 +01:00
dependabot[bot] 9c85e63354 refactor: Bump es5-ext from 0.10.62 to 0.10.63 (#8953) 2024-02-27 14:42:32 +01:00
Parse Platform ab58eee0de refactor: Upgrade uuid from 9.0.0 to 9.0.1 (#8950) 2024-02-27 14:08:08 +01:00
Parse Platform ec5a8ccbfd refactor: Upgrade redis from 4.6.11 to 4.6.13 (#8948) 2024-02-27 00:21:45 +01:00
Parse Platform 763738c92b refactor: Upgrade otpauth from 9.2.1 to 9.2.2 (#8951) 2024-02-26 22:44:46 +01:00
Parse Platform 6579e8254c refactor: Upgrade ws from 8.15.1 to 8.16.0 (#8952) 2024-02-26 22:18:13 +01:00
Manuel f5d6fc98e7 refactor: Upgrade ldapjs from 2.3.3 to 3.0.7 (#8947) 2024-02-26 21:05:10 +01:00
Parse Platform 68b745a604 refactor: Upgrade follow-redirects from 1.15.4 to 1.15.5 (#8946) 2024-02-26 01:21:01 +01:00
dependabot[bot] 94846cd4de refactor: Bump ip from 1.1.5 to 2.0.1 (#8941) 2024-02-25 02:26:48 +01:00
Parse Platform 1d80aa25e3 refactor: Upgrade winston from 3.8.2 to 3.11.0 (#8939) 2024-02-24 23:30:06 +01:00
Parse Platform 597a9c3163 refactor: Upgrade semver from 7.5.2 to 7.5.4 (#8940) 2024-02-24 17:29:20 +01:00
dependabot[bot] 1f6dadbb81 refactor: Upgrade ip from 1.1.5 to 2.0.1 (#8936) 2024-02-22 20:39:23 +01:00
Parse Platform ac7399b226 refactor: Upgrade jwks-rsa from 2.1.5 to 3.1.0 (#8926) 2024-02-18 14:27:31 +01:00
Parse Platform 9001df5063 refactor: Upgrade @parse/fs-files-adapter from 1.2.2 to 2.0.1 (#8925) 2024-02-18 13:16:20 +01:00
semantic-release-bot a6d574ede6 chore(release): 7.0.0-alpha.19 [skip ci]
# [7.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.18...7.0.0-alpha.19) (2024-02-15)

### Features

* Node process exits with error code 1 on uncaught exception to allow custom uncaught exception handling ([#8894](https://github.com/parse-community/parse-server/issues/8894)) ([70c280c](https://github.com/parse-community/parse-server/commit/70c280ca578ff28b5acf92f37fbe06d42a5b34ca))

### BREAKING CHANGES

* Node process now exits with code 1 on uncaught exceptions, enabling custom handlers that were blocked by Parse Server's default behavior of re-throwing errors. This change may lead to automatic process restarts by the environment, unlike before. ([70c280c](70c280c))
2024-02-15 23:19:24 +00:00
Onur 70c280ca57 feat: Node process exits with error code 1 on uncaught exception to allow custom uncaught exception handling (#8894)
BREAKING CHANGE: Node process now exits with code 1 on uncaught exceptions, enabling custom handlers that were blocked by Parse Server's default behavior of re-throwing errors. This change may lead to automatic process restarts by the environment, unlike before.
2024-02-16 00:18:29 +01:00
Parse Platform e73bc517a8 refactor: Upgrade redis from 4.6.6 to 4.6.11 (#8880) 2024-02-15 13:24:46 +01:00
Parse Platform 25796537f4 refactor: Upgrade ws from 8.13.0 to 8.15.1 (#8878) 2024-02-15 13:09:23 +01:00
Parse Platform efc5897f0b refactor: Upgrade lru-cache from 9.1.1 to 10.1.0 (#8877) 2024-02-15 12:48:31 +01:00
Corey 5202212b0b refactor: Remove deprecated bcrypt-nodejs package (#8902) 2024-02-15 12:08:39 +01:00
Parse Platform c604657a27 refactor: Upgrade otpauth from 9.1.2 to 9.2.1 (#8879) 2024-02-15 03:31:37 +01:00
Corey 514c2377e0 refactor: Upgrade pg-promise from 11.5.0 to 11.5.4 (#8900) 2024-02-15 02:51:55 +01:00
Corey dfd1aee7dd docs: Update testing against Postgres locally (#8906) 2024-02-15 02:32:58 +01:00
semantic-release-bot af686f31da chore(release): 7.0.0-alpha.18 [skip ci]
# [7.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.17...7.0.0-alpha.18) (2024-02-15)

### Features

* Deprecation DEPPS6: Authentication adapters disabled by default ([#8858](https://github.com/parse-community/parse-server/issues/8858)) ([0cf58eb](https://github.com/parse-community/parse-server/commit/0cf58eb8d60c8e5f485764e154f3214c49eee430))

### BREAKING CHANGES

* Authentication adapters are disabled by default; to use an authentication adapter it needs to be explicitly enabled in the Parse Server authentication adapter option `auth.<provider>.enabled: true` ([0cf58eb](0cf58eb))
2024-02-15 00:28:56 +00:00
Onur 0cf58eb8d6 feat: Deprecation DEPPS6: Authentication adapters disabled by default (#8858)
BREAKING CHANGE: Authentication adapters are disabled by default; to use an authentication adapter it needs to be explicitly enabled in the Parse Server authentication adapter option `auth.<provider>.enabled: true`
2024-02-15 01:28:09 +01:00
semantic-release-bot 0e9b6d69ef chore(release): 7.0.0-alpha.17 [skip ci]
# [7.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.16...7.0.0-alpha.17) (2024-02-15)

### Features

* Deprecation DEPPS8:  Parse Server option `allowExpiredAuthDataToken` defaults to `false` ([#8860](https://github.com/parse-community/parse-server/issues/8860)) ([e29845f](https://github.com/parse-community/parse-server/commit/e29845f8dacac09ce3093d75c0d92330c24389e8))

### BREAKING CHANGES

* Parse Server option `allowExpiredAuthDataToken` defaults to `false`; a 3rd party authentication token will be validated every time the user tries to log in and the login will fail if the token has expired; the effect of this change may differ for different authentication adapters, depending on the token lifetime and the token refresh logic of the adapter ([e29845f](e29845f))
2024-02-15 00:08:37 +00:00
Onur e29845f8da feat: Deprecation DEPPS8: Parse Server option allowExpiredAuthDataToken defaults to false (#8860)
BREAKING CHANGE: Parse Server option `allowExpiredAuthDataToken` defaults to `false`; a 3rd party authentication token will be validated every time the user tries to log in and the login will fail if the token has expired; the effect of this change may differ for different authentication adapters, depending on the token lifetime and the token refresh logic of the adapter
2024-02-15 01:07:35 +01:00
semantic-release-bot bbda8d2ed6 chore(release): 7.0.0-alpha.16 [skip ci]
# [7.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.15...7.0.0-alpha.16) (2024-02-14)

### Features

* Deprecation DEPPS9: LiveQuery `fields` option is renamed to `keys` ([#8852](https://github.com/parse-community/parse-server/issues/8852)) ([38983e8](https://github.com/parse-community/parse-server/commit/38983e8e9b5cdbd006f311a2338103624137d013))

### BREAKING CHANGES

* LiveQuery `fields` option is renamed to `keys` ([38983e8](38983e8))
2024-02-14 23:32:04 +00:00
Onur 38983e8e9b feat: Deprecation DEPPS9: LiveQuery fields option is renamed to keys (#8852)
BREAKING CHANGE: LiveQuery `fields` option is renamed to `keys`
2024-02-15 00:31:15 +01:00
semantic-release-bot 359b66f9d1 chore(release): 7.0.0-alpha.15 [skip ci]
# [7.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.14...7.0.0-alpha.15) (2024-02-14)

### Features

* Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax ([#8855](https://github.com/parse-community/parse-server/issues/8855)) ([4e6a375](https://github.com/parse-community/parse-server/commit/4e6a375b5184ae0f7aa256a921eca4021c609435))

### BREAKING CHANGES

* Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'` ([4e6a375](4e6a375))
2024-02-14 21:55:18 +00:00
Onur 4e6a375b51 feat: Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax (#8855)
BREAKING CHANGE: Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'`
2024-02-14 22:54:30 +01:00
semantic-release-bot df3d0bc82d chore(release): 7.0.0-alpha.14 [skip ci]
# [7.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.13...7.0.0-alpha.14) (2024-02-14)

### Bug Fixes

* GraphQL file upload fails in case of use of pointer or relation ([#8721](https://github.com/parse-community/parse-server/issues/8721)) ([1aba638](https://github.com/parse-community/parse-server/commit/1aba6382c873fb489d4a898d301e6da9fb6aa61b))
2024-02-14 20:45:38 +00:00
Antoine Cormouls 1aba6382c8 fix: GraphQL file upload fails in case of use of pointer or relation (#8721) 2024-02-14 21:44:42 +01:00
semantic-release-bot 6f21195980 chore(release): 7.0.0-alpha.13 [skip ci]
# [7.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.12...7.0.0-alpha.13) (2024-02-14)

### Bug Fixes

* Docker image not published to Docker Hub on new release ([#8905](https://github.com/parse-community/parse-server/issues/8905)) ([a2ac8d1](https://github.com/parse-community/parse-server/commit/a2ac8d133c71cd7b61e5ef59c4be915cfea85db6))
2024-02-14 20:06:15 +00:00
Corey a2ac8d133c fix: Docker image not published to Docker Hub on new release (#8905) 2024-02-14 21:05:20 +01:00
semantic-release-bot 27ad6f476a chore(release): 7.0.0-alpha.12 [skip ci]
# [7.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.11...7.0.0-alpha.12) (2024-02-14)

### Features

* Add support for Node 20, drop support for Node 14, 16 ([#8907](https://github.com/parse-community/parse-server/issues/8907)) ([ced4872](https://github.com/parse-community/parse-server/commit/ced487246ea0ef72a8aa014991f003209b34841e))

### BREAKING CHANGES

* Removes support for Node 14 and 16 ([ced4872](ced4872))
2024-02-14 18:57:59 +00:00
Corey ced487246e feat: Add support for Node 20, drop support for Node 14, 16 (#8907)
BREAKING CHANGE: Removes support for Node 14 and 16
2024-02-14 19:56:49 +01:00
semantic-release-bot 104990b52a chore(release): 7.0.0-alpha.11 [skip ci]
# [7.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.10...7.0.0-alpha.11) (2024-01-22)

### Features

* Add support for Postgres 16 ([#8898](https://github.com/parse-community/parse-server/issues/8898)) ([99489b2](https://github.com/parse-community/parse-server/commit/99489b22e4f0982e6cb39992974b51aa8d3a31e4))

### BREAKING CHANGES

* Removes support for Postgres 11 and 12 ([99489b2](99489b2))
2024-01-22 18:59:08 +00:00
Corey 99489b22e4 feat: Add support for Postgres 16 (#8898)
BREAKING CHANGE: Removes support for Postgres 11 and 12
2024-01-22 19:58:08 +01:00
semantic-release-bot 655e2c41f0 chore(release): 7.0.0-alpha.10 [skip ci]
# [7.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.9...7.0.0-alpha.10) (2024-01-17)

### Features

* Add password validation via POST request for user with unverified email using master key and option `ignoreEmailVerification` ([#8895](https://github.com/parse-community/parse-server/issues/8895)) ([633a9d2](https://github.com/parse-community/parse-server/commit/633a9d25e4253e2125bc93c02ee8a37e0f5f7b83))
2024-01-17 16:43:59 +00:00
Manuel 633a9d25e4 feat: Add password validation via POST request for user with unverified email using master key and option ignoreEmailVerification (#8895) 2024-01-17 17:43:04 +01:00
semantic-release-bot abdba68380 chore(release): 7.0.0-alpha.9 [skip ci]
# [7.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.8...7.0.0-alpha.9) (2024-01-15)

### Bug Fixes

* Server crashes when receiving an array of `Parse.Pointer` in the request body ([#8784](https://github.com/parse-community/parse-server/issues/8784)) ([66e3603](https://github.com/parse-community/parse-server/commit/66e36039d8af654cfa0284666c0ddd94975dcb52))
2024-01-15 15:03:58 +00:00
Ziv Chen 66e36039d8 fix: Server crashes when receiving an array of Parse.Pointer in the request body (#8784) 2024-01-15 16:02:57 +01:00
semantic-release-bot 038b7a978b chore(release): 7.0.0-alpha.8 [skip ci]
# [7.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.7...7.0.0-alpha.8) (2024-01-15)

### Bug Fixes

* Incomplete user object in `verifyEmail` function if both username and email are changed ([#8889](https://github.com/parse-community/parse-server/issues/8889)) ([1eb95ae](https://github.com/parse-community/parse-server/commit/1eb95aeb41a96250e582d79a703f6adcb403c08b))
2024-01-15 14:45:47 +00:00
Manuel 1eb95aeb41 fix: Incomplete user object in verifyEmail function if both username and email are changed (#8889) 2024-01-15 15:44:49 +01:00
semantic-release-bot 355baf9dfc chore(release): 7.0.0-alpha.7 [skip ci]
# [7.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.6...7.0.0-alpha.7) (2024-01-14)

### Bug Fixes

* Username is `undefined` in email verification link on email change ([#8887](https://github.com/parse-community/parse-server/issues/8887)) ([e315c13](https://github.com/parse-community/parse-server/commit/e315c137bf41bedfa8f0df537f2c3f6ab45b7e60))
2024-01-14 23:48:19 +00:00
Manuel e315c137bf fix: Username is undefined in email verification link on email change (#8887) 2024-01-15 00:47:03 +01:00
semantic-release-bot 3c07fcada6 chore(release): 7.0.0-alpha.6 [skip ci]
# [7.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.5...7.0.0-alpha.6) (2024-01-14)

### Bug Fixes

* Parse Server option `emailVerifyTokenReuseIfValid: true` generates new token on every email verification request ([#8885](https://github.com/parse-community/parse-server/issues/8885)) ([0023ce4](https://github.com/parse-community/parse-server/commit/0023ce448a5e9423337d0e1a25648bde1156bc95))
2024-01-14 00:38:12 +00:00
Manuel 0023ce448a fix: Parse Server option emailVerifyTokenReuseIfValid: true generates new token on every email verification request (#8885) 2024-01-14 01:37:20 +01:00
semantic-release-bot 4aba66c620 chore(release): 7.0.0-alpha.5 [skip ci]
# [7.0.0-alpha.5](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.4...7.0.0-alpha.5) (2024-01-06)

### Features

* Add `installationId`, `ip`, `resendRequest` to arguments passed to `verifyUserEmails` on verification email request ([#8873](https://github.com/parse-community/parse-server/issues/8873)) ([8adcbee](https://github.com/parse-community/parse-server/commit/8adcbee11283d3e95179ca2047e2615f52c18806))

### BREAKING CHANGES

* The `Parse.User` passed as argument if `verifyUserEmails` is set to a function is renamed from `user` to `object` for consistency with invocations of `verifyUserEmails` on signup or login; the user object is not a plain JavaScript object anymore but an instance of `Parse.User` ([8adcbee](8adcbee))
2024-01-06 15:42:07 +00:00
Manuel 8adcbee112 feat: Add installationId, ip, resendRequest to arguments passed to verifyUserEmails on verification email request (#8873)
BREAKING CHANGE: The `Parse.User` passed as argument if `verifyUserEmails` is set to a function is renamed from `user` to `object` for consistency with invocations of `verifyUserEmails` on signup or login; the user object is not a plain JavaScript object anymore but an instance of `Parse.User`
2024-01-06 16:41:13 +01:00
Parse Platform 0d58e3972c refactor: Security upgrade follow-redirects from 1.15.2 to 1.15.4 (#8857) 2024-01-02 12:03:05 +01:00
semantic-release-bot 3b9f50ac90 chore(release): 7.0.0-alpha.4 [skip ci]
# [7.0.0-alpha.4](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.3...7.0.0-alpha.4) (2023-12-27)

### Features

* Add `Parse.User` as function parameter to Parse Server options `verifyUserEmails`, `preventLoginWithUnverifiedEmail` on login ([#8850](https://github.com/parse-community/parse-server/issues/8850)) ([972f630](https://github.com/parse-community/parse-server/commit/972f6300163b3cd7d95eeb95986e8322c95f821c))
2023-12-27 23:35:51 +00:00
Manuel 972f630016 feat: Add Parse.User as function parameter to Parse Server options verifyUserEmails, preventLoginWithUnverifiedEmail on login (#8850) 2023-12-28 00:34:58 +01:00
semantic-release-bot 19fc5461d5 chore(release): 7.0.0-alpha.3 [skip ci]
# [7.0.0-alpha.3](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.2...7.0.0-alpha.3) (2023-12-26)

### Bug Fixes

* Conditional email verification not working in some cases if `verifyUserEmails`, `preventLoginWithUnverifiedEmail` set to functions ([#8838](https://github.com/parse-community/parse-server/issues/8838)) ([8e7a6b1](https://github.com/parse-community/parse-server/commit/8e7a6b1480c0117e6c73e7adc5a6619115a04e85))

### Features

* Allow `Parse.Session.current` on expired session token instead of throwing error ([#8722](https://github.com/parse-community/parse-server/issues/8722)) ([f9dde4a](https://github.com/parse-community/parse-server/commit/f9dde4a9f8a90c63f71172c9bc515b0f6c6d2e4a))

### BREAKING CHANGES

* `Parse.Session.current()` no longer throws an error if the session token is expired, but instead returns the session token with its expiration date to allow checking its validity ([f9dde4a](f9dde4a))
2023-12-26 23:59:06 +00:00
Manuel 69c927c907 ci: Auto-release not working due to more than 3 release branches (#8847) 2023-12-27 00:58:11 +01:00
Manuel 8e7a6b1480 fix: Conditional email verification not working in some cases if verifyUserEmails, preventLoginWithUnverifiedEmail set to functions (#8838) 2023-12-26 21:01:27 +01:00
Diamond Lewis f9dde4a9f8 feat: Allow Parse.Session.current on expired session token instead of throwing error (#8722)
BREAKING CHANGE: `Parse.Session.current()` no longer throws an error if the session token is expired, but instead returns the session token with its expiration date to allow checking its validity
2023-12-25 20:40:49 +01:00
semantic-release-bot a22f095a47 chore(release): 7.0.0-alpha.2 [skip ci]
# [7.0.0-alpha.2](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.1...7.0.0-alpha.2) (2023-12-17)

### Features

* Add `installationId` to arguments for `verifyUserEmails`, `preventLoginWithUnverifiedEmail` ([#8836](https://github.com/parse-community/parse-server/issues/8836)) ([a22dbe1](https://github.com/parse-community/parse-server/commit/a22dbe16d5ac0090608f6caaf0ebd134925b7fd4))
2023-12-17 00:51:12 +00:00
Manuel a22dbe16d5 feat: Add installationId to arguments for verifyUserEmails, preventLoginWithUnverifiedEmail (#8836) 2023-12-17 01:50:19 +01:00
semantic-release-bot 2c2563ebd2 chore(release): 7.0.0-alpha.1 [skip ci]
# [7.0.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.5.0-alpha.2...7.0.0-alpha.1) (2023-12-10)

### Features

* Add support for MongoDB 7 ([#8761](https://github.com/parse-community/parse-server/issues/8761)) ([3de8494](https://github.com/parse-community/parse-server/commit/3de8494a221991dfd10a74e0a2dc89576265c9b7))

### BREAKING CHANGES

* `Parse.Query` no longer supports the BSON type `code`; although this feature was never officially documented, its removal is announced as a breaking change to protect deployments where it might be in use. ([3de8494](3de8494))
2023-12-10 01:43:37 +00:00
Lucas Coratger 3de8494a22 feat: Add support for MongoDB 7 (#8761)
BREAKING CHANGE: `Parse.Query` no longer supports the BSON type `code`; although this feature was never officially documented, its removal is announced as a breaking change to protect deployments where it might be in use.
2023-12-10 02:42:40 +01:00
semantic-release-bot d3087ed69f chore(release): 6.5.0-alpha.2 [skip ci]
# [6.5.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.5.0-alpha.1...6.5.0-alpha.2) (2023-11-19)

### Performance Improvements

* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522))
2023-11-19 22:14:13 +00:00
Antoine Cormouls b87daba067 perf: Improved IP validation performance for masterKeyIPs, maintenanceKeyIPs (#8510) 2023-11-19 23:13:16 +01:00
Manuel 759731926f docs: Improve docs for Parse Server options masterKeyIps, maintenanceKeyIps (#8814) 2023-11-18 15:41:16 +01:00
semantic-release-bot 0762ba6b79 chore(release): 6.5.0-alpha.1 [skip ci]
# [6.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-alpha.1) (2023-11-18)

### Bug Fixes

* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3))
* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a))
* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c))
* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1))

### Features

* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29))
* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620))
* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d))
* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d))
* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740))
2023-11-18 13:54:18 +00:00
Manuel 6ef1986c03 feat: Upgrade Parse Server Push Adapter to 5.0.2 (#8813) 2023-11-18 14:53:21 +01:00
semantic-release-bot 988ecdac54 chore(release): 6.5.0-beta.1 [skip ci]
# [6.5.0-beta.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-beta.1) (2023-11-16)

### Bug Fixes

* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3))
* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a))
* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c))
* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1))

### Features

* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29))
* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620))
* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d))
* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d))
2023-11-16 15:57:46 +00:00
Manuel 87059ae1d6 build: Release (#8810) 2023-11-16 16:56:44 +01:00
Manuel Trezza 42e2e12956 release 2023-11-16 16:43:24 +01:00
Manuel Trezza d58032d39d Merge branch 'beta' into build-release
* beta:
  chore(release): 6.4.0 [skip ci]
  release
  refactor: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8780)
  chore(release): 6.3.1 [skip ci]
  fix: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8781)
2023-11-16 16:41:43 +01:00
semantic-release-bot 5b1bb598e4 chore(release): 6.4.0 [skip ci]
# [6.4.0](https://github.com/parse-community/parse-server/compare/6.3.1...6.4.0) (2023-11-16)

### Bug Fixes

* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b))
* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49))
* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec))
* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64))

### Features

* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a))
* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298))
* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589))

### Performance Improvements

* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd))
2023-11-16 15:26:18 +00:00
Manuel 2612a387ce build: Release (#8809) 2023-11-16 16:25:13 +01:00
Manuel Trezza c6355cda73 release 2023-11-16 15:58:24 +01:00
Manuel Trezza 90aac622b0 Merge branch 'release' into build-release
* release:
  chore(release): 6.3.1 [skip ci]
  fix: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8781)
2023-11-16 15:57:43 +01:00
semantic-release-bot 4b3ce20300 chore(release): 6.4.0-alpha.8 [skip ci]
# [6.4.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.7...6.4.0-alpha.8) (2023-11-13)

### Features

* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620))
2023-11-13 22:33:43 +00:00
Mattia Faraci 09fbeebba8 feat: Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options enableCollationCaseComparison, transformEmailToLowercase, transformUsernameToLowercase (#8805) 2023-11-13 23:32:47 +01:00
Manuel 80b987d00d test: Improve test for $setOnInsert (#8793) 2023-10-25 20:32:58 +02:00
semantic-release-bot 9e0094980f chore(release): 6.4.0-alpha.7 [skip ci]
# [6.4.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.6...6.4.0-alpha.7) (2023-10-25)

### Features

* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29))
2023-10-25 17:14:37 +00:00
Manuel f630a45aa5 feat: Add $setOnInsert operator to Parse.Server.database.update (#8791) 2023-10-25 19:13:27 +02:00
Manuel ea57a7706d refactor: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8780) 2023-10-21 01:03:31 +02:00
Manuel fe02d3e8aa refactor: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8779) 2023-10-21 01:03:02 +02:00
semantic-release-bot b0c012e835 chore(release): 6.3.1 [skip ci]
## [6.3.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.3.1) (2023-10-20)

### Bug Fixes

* Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) ([#8781](https://github.com/parse-community/parse-server/issues/8781)) ([fd86278](https://github.com/parse-community/parse-server/commit/fd86278919556d3682e7e2c856dfccd5beffbfc0))
2023-10-20 23:02:48 +00:00
Manuel fd86278919 fix: Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) (#8781) 2023-10-21 01:01:35 +02:00
semantic-release-bot 5dd3aa0d48 chore(release): 6.4.0-alpha.6 [skip ci]
# [6.4.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.5...6.4.0-alpha.6) (2023-10-18)

### Bug Fixes

* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c))
2023-10-18 21:46:43 +00:00
dependabot[bot] 2d6b3d1849 fix: Security bump @babel/traverse from 7.20.5 to 7.23.2 (#8777) 2023-10-18 23:45:24 +02:00
Doug Drechsel 93af48a8b4 ci: Add ability to exclude tests via ID in testExclusionList.json (#8774) 2023-10-18 22:39:41 +02:00
semantic-release-bot 5462834240 chore(release): 6.4.0-alpha.5 [skip ci]
# [6.4.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.4...6.4.0-alpha.5) (2023-10-14)

### Bug Fixes

* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3))
2023-10-14 00:58:51 +00:00
Rikard Teodorsson 7d32d8934f fix: Context not passed to Cloud Code Trigger beforeFind when using Parse.Query.include (#8765) 2023-10-14 02:57:47 +02:00
dependabot[bot] 8d3117e0bc refactor: Bump postcss from 8.4.20 to 8.4.31 (#8771) 2023-10-07 13:29:46 +02:00
semantic-release-bot a2a98b1684 chore(release): 6.4.0-alpha.4 [skip ci]
# [6.4.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.3...6.4.0-alpha.4) (2023-09-29)

### Features

* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d))
2023-09-29 20:18:59 +00:00
Wes 77bbfb3f18 feat: Allow setting createdAt and updatedAt during Parse.Object creation with maintenance key (#8696) 2023-09-29 22:17:48 +02:00
semantic-release-bot 9b9c3a4214 chore(release): 6.4.0-alpha.3 [skip ci]
# [6.4.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.2...6.4.0-alpha.3) (2023-09-23)

### Bug Fixes

* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a))
2023-09-23 20:44:36 +00:00
Marc Derhammer 3d6d50e0af fix: Parse Server option fileUpload.fileExtensions fails to determine file extension if filename contains multiple dots (#8754) 2023-09-23 22:43:34 +02:00
semantic-release-bot b70c2d9027 chore(release): 6.4.0-alpha.2 [skip ci]
# [6.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.1...6.4.0-alpha.2) (2023-09-22)

### Bug Fixes

* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1))
2023-09-22 01:23:36 +00:00
dependabot[bot] 71dfd8a7ec fix: Security upgrade graphql from 16.6.0 to 16.8.1 (#8758) 2023-09-22 03:22:33 +02:00
Manuel 39a91d0d77 docs: fix incorrect alpha changelog (#8756) 2023-09-20 15:13:03 +02:00
semantic-release-bot 4945ab7520 chore(release): 6.4.0-alpha.1 [skip ci]
# [6.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-alpha.1) (2023-09-20)

### Bug Fixes

* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b))
* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49))
* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec))
* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64))

### Features

* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a))
* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d))
* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298))
* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589))

### Performance Improvements

* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd))
2023-09-20 08:48:52 +00:00
Diamond Lewis a9c34ef1e2 feat: Add context to Cloud Code Triggers beforeLogin and afterLogin (#8724) 2023-09-20 10:47:35 +02:00
semantic-release-bot 05939858af chore(release): 6.4.0-beta.1 [skip ci]
# [6.4.0-beta.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-beta.1) (2023-09-16)

### Bug Fixes

* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b))
* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49))
* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec))
* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64))

### Features

* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a))
* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298))
* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589))

### Performance Improvements

* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd))
2023-09-16 02:52:34 +00:00
Manuel f5e20f9121 build: Release (#8749) 2023-09-16 04:51:10 +02:00
Manuel Trezza 9c6cdf4904 release 2023-09-16 03:25:46 +02:00
Manuel Trezza 4baeae4f4f Merge branch 'beta' into build
* beta:
  chore(release): 6.3.0 [skip ci]
  release
  refactor: Parse Pointer allows to access internal Parse Server classes and circumvent `beforeFind` query trigger (#8734)
  chore(release): 6.2.2 [skip ci]
  fix: Parse Pointer allows to access internal Parse Server classes and circumvent `beforeFind` query trigger; fixes security vulnerability [GHSA-fcv6-fg5r-jm9q](https://github.com/parse-community/parse-server/security/advisories/GHSA-fcv6-fg5r-jm9q)
  refactor: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) (#8677)
  chore(release): 6.2.1 [skip ci]
  fix: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) (#8674)
  refactor: Add option to convert `Parse.Object` to instance in Cloud Function payload (#8656)
2023-09-16 03:25:21 +02:00
semantic-release-bot 3602ecb169 chore(release): 6.3.0 [skip ci]
# [6.3.0](https://github.com/parse-community/parse-server/compare/6.2.2...6.3.0) (2023-09-16)

### Bug Fixes

* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804))
* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394))
* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4))
* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b))
* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e))
* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae))

### Features

* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029))
* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab))
* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d))
* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e))
* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e))
* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761))

### Reverts

* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff))
2023-09-16 01:08:49 +00:00
Manuel 7f89399300 build: Release (#8748) 2023-09-16 03:07:43 +02:00
Manuel Trezza 88a9106956 release 2023-09-16 02:25:35 +02:00
Manuel Trezza 391c7a02aa Merge branch 'release' into build
* release:
  chore(release): 6.2.2 [skip ci]
  fix: Parse Pointer allows to access internal Parse Server classes and circumvent `beforeFind` query trigger; fixes security vulnerability [GHSA-fcv6-fg5r-jm9q](https://github.com/parse-community/parse-server/security/advisories/GHSA-fcv6-fg5r-jm9q)
  chore(release): 6.2.1 [skip ci]
  fix: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) (#8674)
2023-09-16 02:22:36 +02:00
semantic-release-bot 6ea65f255f chore(release): 6.3.0-alpha.9 [skip ci]
# [6.3.0-alpha.9](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.8...6.3.0-alpha.9) (2023-09-13)

### Performance Improvements

* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd))
2023-09-13 12:17:51 +00:00
Yechezkel Deren 45a3ed0fcf perf: Improve performance of recursive pointer iterations (#8741) 2023-09-13 14:16:33 +02:00
Manuel 977edeaf28 test: Add tests for isGet parameter in Cloud Code trigger beforeFind (#8738) 2023-09-06 02:42:50 +02:00
Manuel 739ffbed86 refactor: Parse Pointer allows to access internal Parse Server classes and circumvent beforeFind query trigger (#8734) 2023-09-04 16:01:22 +02:00
Manuel 5954f0ffa0 refactor: Parse Pointer allows to access internal Parse Server classes and circumvent beforeFind query trigger (#8735) 2023-09-04 16:01:02 +02:00
semantic-release-bot d141b822ad chore(release): 6.2.2 [skip ci]
## [6.2.2](https://github.com/parse-community/parse-server/compare/6.2.1...6.2.2) (2023-09-04)

### Bug Fixes

* Parse Pointer allows to access internal Parse Server classes and circumvent `beforeFind` query trigger; fixes security vulnerability [GHSA-fcv6-fg5r-jm9q](https://github.com/parse-community/parse-server/security/advisories/GHSA-fcv6-fg5r-jm9q) ([be4c7e2](https://github.com/parse-community/parse-server/commit/be4c7e23c63a2fb690685665cebed0de26be05c5))
2023-09-04 12:20:56 +00:00
Manuel be4c7e23c6 fix: Parse Pointer allows to access internal Parse Server classes and circumvent beforeFind query trigger; fixes security vulnerability [GHSA-fcv6-fg5r-jm9q](https://github.com/parse-community/parse-server/security/advisories/GHSA-fcv6-fg5r-jm9q) 2023-09-04 14:19:48 +02:00
semantic-release-bot 877eede075 chore(release): 6.3.0-alpha.8 [skip ci]
# [6.3.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.7...6.3.0-alpha.8) (2023-08-30)

### Bug Fixes

* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49))
2023-08-30 00:53:25 +00:00
Cory Imdieke 2b3d4e5d3c fix: Redis 4 does not reconnect after unhandled error (#8706) 2023-08-30 02:52:13 +02:00
dependabot[bot] 42929e0e5e build(deps): Bump word-wrap from 1.2.3 to 1.2.5 (#8708) 2023-08-21 19:44:33 +02:00
semantic-release-bot b9bdca4520 chore(release): 6.3.0-alpha.7 [skip ci]
# [6.3.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.6...6.3.0-alpha.7) (2023-08-18)

### Bug Fixes

* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec))
2023-08-18 00:24:55 +00:00
Manuel ae68f0c31b fix: Remove config logging when launching Parse Server via CLI (#8710) 2023-08-18 02:11:24 +02:00
Parse Platform 7a198f4eed refactor: Security upgrade @parse/push-adapter from 4.1.3 to 4.2.0 (#8707) 2023-08-07 01:39:05 +02:00
semantic-release-bot 95da5d64c1 chore(release): 6.3.0-alpha.6 [skip ci]
# [6.3.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.5...6.3.0-alpha.6) (2023-07-17)

### Bug Fixes

* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b))
2023-07-17 22:35:58 +00:00
Bartosz Marganiec 6a4a00ca7a fix: Parse Server option fileUpload.fileExtensions does not work with an array of extensions (#8688) 2023-07-18 00:34:46 +02:00
Daniel c9b59719ec refactor: Change response types of TOTP adapter to match existing adapters (#8661) 2023-07-06 17:22:18 +02:00
semantic-release-bot 02f40fd896 chore(release): 6.3.0-alpha.5 [skip ci]
# [6.3.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.4...6.3.0-alpha.5) (2023-07-05)

### Features

* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298))
2023-07-05 20:12:35 +00:00
Daniel a9d376b61f feat: Add property Parse.Server.version to determine current version of Parse Server in Cloud Code (#8670) 2023-07-05 22:11:35 +02:00
semantic-release-bot a742656a90 chore(release): 6.3.0-alpha.4 [skip ci]
# [6.3.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.3...6.3.0-alpha.4) (2023-07-04)

### Bug Fixes

* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64))
2023-07-04 11:18:02 +00:00
Daniel 4e2000bc56 fix: Server does not start via CLI when auth option is set (#8666) 2023-07-04 13:16:55 +02:00
Parse Platform 446cbb1a31 refactor: Upgrade otpauth from 9.0.2 to 9.1.2 (#8668) 2023-06-30 02:29:08 +02:00
Corey 3f03bd3c6f refactor: Remove duplicate user index creation (#8662) 2023-06-30 01:15:58 +02:00
Manuel 31805c96ec refactor: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) (#8676) 2023-06-28 23:38:14 +02:00
Manuel d6b17baa32 refactor: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) (#8677) 2023-06-28 23:37:25 +02:00
semantic-release-bot 328918178f chore(release): 6.2.1 [skip ci]
## [6.2.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.2.1) (2023-06-28)

### Bug Fixes

* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) ([#8674](https://github.com/parse-community/parse-server/issues/8674)) ([3dd99dd](https://github.com/parse-community/parse-server/commit/3dd99dd80e27e5e1d99b42844180546d90c7aa90))
2023-06-28 20:58:52 +00:00
Manuel 3dd99dd80e fix: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) (#8674) 2023-06-28 22:57:25 +02:00
semantic-release-bot f8b5a99d54 chore(release): 6.3.0-alpha.3 [skip ci]
# [6.3.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.2...6.3.0-alpha.3) (2023-06-23)

### Features

* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589))
2023-06-23 15:59:00 +00:00
Daniel cc079a40f6 feat: Add TOTP authentication adapter (#8457) 2023-06-23 17:57:57 +02:00
Manuel 3ec3e40dc8 docs: Fix deprecation date (#8657) 2023-06-23 16:36:08 +02:00
Daniel 068fb9e777 refactor: Add option to convert Parse.Object to instance in Cloud Function payload (#8646) 2023-06-23 16:29:54 +02:00
Manuel e212eb5195 refactor: Add option to convert Parse.Object to instance in Cloud Function payload (#8656) 2023-06-23 16:29:32 +02:00
Parse Platform 1850be45b1 refactor: Security upgrade semver from 7.5.1 to 7.5.2 (#8650) 2023-06-22 00:42:42 +02:00
semantic-release-bot e6bd2baf71 chore(release): 6.3.0-alpha.2 [skip ci]
# [6.3.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.1...6.3.0-alpha.2) (2023-06-20)

### Features

* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a))
2023-06-20 10:12:02 +00:00
Daniel 44acd6d9ed feat: Add conditional email verification via dynamic Parse Server options verifyUserEmails, sendUserEmailVerification that now accept functions (#8425) 2023-06-20 12:10:25 +02:00
Corey 3710da7379 refactor: Replace deprecated substr with substring (#8644) 2023-06-20 12:07:10 +02:00
semantic-release-bot 9674d4a2c0 chore(release): 6.3.0-alpha.1 [skip ci]
# [6.3.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.3.0-alpha.1) (2023-06-18)

### Bug Fixes

* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804))
* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394))
* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4))
* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b))
* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e))
* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae))

### Features

* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029))
* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab))
* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d))
* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e))
* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e))
* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761))

### Reverts

* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff))
2023-06-18 01:20:54 +00:00
Manuel 45301a67e8 docs: Fix broken logo link in API docs (#8642) 2023-06-18 03:19:07 +02:00
semantic-release-bot 4ad0800508 chore(release): 6.3.0-beta.1 [skip ci]
# [6.3.0-beta.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.3.0-beta.1) (2023-06-10)

### Bug Fixes

* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804))
* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394))
* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4))
* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b))
* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e))
* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae))

### Features

* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029))
* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab))
* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d))
* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e))
* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e))
* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761))

### Reverts

* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff))
2023-06-10 23:05:13 +00:00
Manuel e2e51d94fa build: Release (#8627) 2023-06-11 01:04:06 +02:00
Manuel Trezza 0c3382fbab Merge branch 'beta' into build 2023-06-10 23:13:23 +02:00
Manuel Trezza 24c0b03f5e Squashed commit of the following:
commit 150627328f
Author: semantic-release-bot <semantic-release-bot@martynus.net>
Date:   Sat May 20 23:24:03 2023 +0000

    chore(release): 6.2.0 [skip ci]

    # [6.2.0](https://github.com/parse-community/parse-server/compare/6.1.0...6.2.0) (2023-05-20)

    ### Features

    * Add new Parse Server option `fileUpload.fileExtensions` to restrict file upload by file extension; this fixes a security vulnerability in which a phishing attack could be performed using an uploaded HTML file; by default the new option only allows file extensions matching the regex pattern `^[^hH][^tT][^mM][^lL]?$`, which excludes HTML files; if your app currently depends on uploading files with HTML file extensions then this may be a breaking change and you could allow HTML file upload by setting the option to `['.*']` ([#8538](https://github.com/parse-community/parse-server/issues/8538)) ([a318e7b](https://github.com/parse-community/parse-server/commit/a318e7bbafcf7a3425b0a1b3c2dd30f526b4b6f9))

commit a318e7bbaf
Author: Manuel <5673677+mtrezza@users.noreply.github.com>
Date:   Sun May 21 01:23:00 2023 +0200

    feat: Add new Parse Server option `fileUpload.fileExtensions` to restrict file upload by file extension; this fixes a security vulnerability in which a phishing attack could be performed using an uploaded HTML file; by default the new option only allows file extensions matching the regex pattern `^[^hH][^tT][^mM][^lL]?$`, which excludes HTML files; if your app currently depends on uploading files with HTML file extensions then this may be a breaking change and you could allow HTML file upload by setting the option to `['.*']` (#8538)

commit 832702dffd
Author: semantic-release-bot <semantic-release-bot@martynus.net>
Date:   Mon May 1 21:50:23 2023 +0000

    chore(release): 6.1.0 [skip ci]

    # [6.1.0](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0) (2023-05-01)

    ### Bug Fixes

    * LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
    * Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
    * Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
    * Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))
    * Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))

    ### Features

    * Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
    * Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
    * Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
    * Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
    * Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
    * Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
    * Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))

commit 18b63d1da7
Merge: f7eee19d f59d46c9
Author: Manuel <5673677+mtrezza@users.noreply.github.com>
Date:   Mon May 1 23:49:22 2023 +0200

    build: Release (#8526)
2023-06-10 23:11:12 +02:00
Manuel Trezza fb54ac1f1e empty commit 2023-06-10 23:11:12 +02:00
Manuel 02a2ef2baa docs: Fix typos in CONTRIBUTING guide (#8629) 2023-06-10 23:08:43 +02:00
Manuel 234fb2cbf3 docs: Add to CONTRIBUTING guide (#8628) 2023-06-10 23:04:48 +02:00
semantic-release-bot c8910abdaa chore(release): 6.1.0-alpha.20 [skip ci]
# [6.1.0-alpha.20](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.19...6.1.0-alpha.20) (2023-06-09)

### Features

* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e))
2023-06-09 11:29:05 +00:00
Daniel 03fba97e05 feat: Add zones for rate limiting by ip, user, session, global (#8508) 2023-06-09 13:27:56 +02:00
semantic-release-bot e2a7218f74 chore(release): 6.1.0-alpha.19 [skip ci]
# [6.1.0-alpha.19](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.18...6.1.0-alpha.19) (2023-06-08)

### Bug Fixes

* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b))
2023-06-08 09:05:50 +00:00
Daniel 967700bdbc fix: LiveQuery server is not shut down properly when handleShutdown is called (#8491) 2023-06-08 11:04:49 +02:00
semantic-release-bot 3ea1ace631 chore(release): 6.1.0-alpha.18 [skip ci]
# [6.1.0-alpha.18](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.17...6.1.0-alpha.18) (2023-06-08)

### Features

* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e))
2023-06-08 02:06:02 +00:00
Corey 656d673cf5 feat: Add support for $eq query constraint in LiveQuery (#8614) 2023-06-08 04:04:58 +02:00
semantic-release-bot b01d4f0abb chore(release): 6.1.0-alpha.17 [skip ci]
# [6.1.0-alpha.17](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.16...6.1.0-alpha.17) (2023-06-07)

### Features

* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab))
2023-06-07 19:53:02 +00:00
Daniel 82da30842a feat: Add new Parse Server option preventSignupWithUnverifiedEmail to prevent returning a user without session token on sign-up with unverified email address (#8451) 2023-06-07 21:51:53 +02:00
Snyk bot 0ce3692759 refactor: Upgrade semver from 7.5.0 to 7.5.1 (#8612) 2023-06-05 10:03:46 +02:00
Parse Platform 8c9a56e8ea refactor: Upgrade parse from 4.0.1 to 4.1.0 (#8604) 2023-06-03 14:16:14 +02:00
Parse Platform 3ec453d885 refactor: Upgrade semver from 7.3.8 to 7.5.0 (#8593) 2023-06-01 16:09:24 +02:00
Parse Platform bf2a224e46 refactor: Upgrade body-parser from 1.20.1 to 1.20.2 (#8594) 2023-05-31 22:09:48 +02:00
Parse Platform 5ab370d58e refactor: Upgrade @babel/eslint-parser from 7.19.1 to 7.21.8 (#8591) 2023-05-31 11:09:10 +02:00
Snyk bot c0d1bc4f72 refactor: Upgrade winston from 3.8.1 to 3.8.2 (#8598) 2023-05-30 20:00:12 +02:00
Parse Platform 15704a68f1 refactor: Upgrade rate-limit-redis from 3.0.1 to 3.0.2 (#8596) 2023-05-29 22:54:41 +02:00
Parse Platform 9f1edd09f7 refactor: Upgrade express-rate-limit from 6.6.0 to 6.7.0 (#8595) 2023-05-29 20:20:43 +02:00
Corey fc3b7526a6 refactor: Upgrade pg-promise from 11.3.0 to 11.5.0 (#8586) 2023-05-29 17:40:51 +02:00
Daniel 505dd6bcfe ci: Fix flaky definitions check (#8504) 2023-05-29 14:11:45 +02:00
semantic-release-bot fc81b411e9 chore(release): 6.1.0-alpha.16 [skip ci]
# [6.1.0-alpha.16](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.15...6.1.0-alpha.16) (2023-05-28)

### Reverts

* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff))
2023-05-28 19:46:01 +00:00
Manuel 6722110f20 revert: fix: Inaccurate table total row count for PostgreSQL
This reverts commit 0823a02fbf.
2023-05-28 21:44:42 +02:00
semantic-release-bot 6c5f89a56b chore(release): 6.1.0-alpha.15 [skip ci]
# [6.1.0-alpha.15](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.14...6.1.0-alpha.15) (2023-05-28)

### Bug Fixes

* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4))
2023-05-28 11:59:52 +00:00
patelmilanun 0823a02fbf fix: Inaccurate table total row count for PostgreSQL (#8511) 2023-05-28 13:32:02 +02:00
Corey 5eb690c1c5 refactor: Incorrect spelling in hooks error message (#8585) 2023-05-28 12:58:16 +02:00
Manuel a37d1ee244 docs: Add code ownership section to CONTRIBUTING guide (#8584) 2023-05-28 01:44:10 +02:00
semantic-release-bot bd39ac54f4 chore(release): 6.1.0-alpha.14 [skip ci]
# [6.1.0-alpha.14](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.13...6.1.0-alpha.14) (2023-05-27)

### Bug Fixes

* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae))

### Features

* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761))
2023-05-27 23:32:51 +00:00
Manuel d7ac0cd9f8 ci: Skip CI for changes in MD files (#8583) 2023-05-28 01:31:42 +02:00
Daniel c2e4f8369b refactor: Upgrade lru-cache from 7.12.0 to 9.1.1 (#8559) 2023-05-25 23:59:42 +02:00
Daniel 28aeda3f16 feat: Allow Parse.Object pointers in Cloud Code arguments (#8490) 2023-05-25 22:02:33 +02:00
Daniel fd6a0077f2 fix: Unnecessary log entries by extendSessionOnUse (#8562) 2023-05-25 14:00:56 +02:00
semantic-release-bot 3030c7652e chore(release): 6.1.0-alpha.13 [skip ci]
# [6.1.0-alpha.13](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.12...6.1.0-alpha.13) (2023-05-25)

### Bug Fixes

* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e))
2023-05-25 11:15:05 +00:00
Daniel f911f2cd3a fix: Rate limit feature is incompatible with Node 14 (#8578) 2023-05-25 13:13:39 +02:00
Snyk bot b0b99e7451 refactor: Security upgrade @parse/push-adapter from 4.1.2 to 4.1.3 (#8572) 2023-05-24 01:39:18 +02:00
Daniel a005874776 refactor: Upgrade commander from 5.1.0 to 10.0.1 (#8557) 2023-05-22 17:11:50 +02:00
Daniel 4c1093e2e4 refactor: Upgrade path-to-regexp from 0.1.7 to 6.2.1 (#8558) 2023-05-22 16:39:32 +02:00
Parse Platform 00c362d739 refactor: Upgrade redis from 4.0.6 to 4.6.6 (#8549) 2023-05-22 00:26:12 +02:00
Parse Platform cc57fafe38 refactor: Upgrade ws from 8.9.0 to 8.13.0 (#8551) 2023-05-21 23:53:17 +02:00
Snyk bot 7121829bbb refactor: Upgrade @graphql-tools/merge from 8.3.6 to 8.4.1 (#8544) 2023-05-21 17:58:23 +02:00
Manuel a27482c57e refactor: Add new Parse Server option fileUpload.fileExtensions to restrict file upload by file extension (#8539) 2023-05-21 01:31:52 +02:00
semantic-release-bot 150627328f chore(release): 6.2.0 [skip ci]
# [6.2.0](https://github.com/parse-community/parse-server/compare/6.1.0...6.2.0) (2023-05-20)

### Features

* Add new Parse Server option `fileUpload.fileExtensions` to restrict file upload by file extension; this fixes a security vulnerability in which a phishing attack could be performed using an uploaded HTML file; by default the new option only allows file extensions matching the regex pattern `^[^hH][^tT][^mM][^lL]?$`, which excludes HTML files; if your app currently depends on uploading files with HTML file extensions then this may be a breaking change and you could allow HTML file upload by setting the option to `['.*']` ([#8538](https://github.com/parse-community/parse-server/issues/8538)) ([a318e7b](https://github.com/parse-community/parse-server/commit/a318e7bbafcf7a3425b0a1b3c2dd30f526b4b6f9))
2023-05-20 23:24:03 +00:00
Manuel a318e7bbaf feat: Add new Parse Server option fileUpload.fileExtensions to restrict file upload by file extension; this fixes a security vulnerability in which a phishing attack could be performed using an uploaded HTML file; by default the new option only allows file extensions matching the regex pattern ^[^hH][^tT][^mM][^lL]?$, which excludes HTML files; if your app currently depends on uploading files with HTML file extensions then this may be a breaking change and you could allow HTML file upload by setting the option to ['.*'] (#8538) 2023-05-21 01:23:00 +02:00
Manuel db4c214eac docs: Add Synk step for LTS release to CONTRIBUTING (#8536) 2023-05-20 23:16:02 +02:00
semantic-release-bot ab301b6518 chore(release): 6.1.0-alpha.12 [skip ci]
# [6.1.0-alpha.12](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.11...6.1.0-alpha.12) (2023-05-19)

### Bug Fixes

* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394))
2023-05-19 06:43:10 +00:00
Daniel d4cda4b26c fix: GridFS file storage doesn't work with certain enableSchemaHooks settings (#8467) 2023-05-19 08:41:48 +02:00
semantic-release-bot c78a5a6f10 chore(release): 6.1.0-alpha.11 [skip ci]
# [6.1.0-alpha.11](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.10...6.1.0-alpha.11) (2023-05-17)

### Features

* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029))
2023-05-17 17:58:54 +00:00
Daniel 6f885d36b9 feat: extendSessionOnUse to automatically renew Parse Sessions (#8505) 2023-05-17 19:49:25 +02:00
semantic-release-bot 559b1de828 chore(release): 6.1.0-alpha.10 [skip ci]
# [6.1.0-alpha.10](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.9...6.1.0-alpha.10) (2023-05-12)

### Bug Fixes

* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804))
2023-05-12 00:41:19 +00:00
Diamond Lewis afd0515e20 fix: Cloud Code Trigger afterSave executes even if not set (#8520) 2023-05-12 02:39:54 +02:00
semantic-release-bot 4187a973cc chore(release): 6.1.0-alpha.9 [skip ci]
# [6.1.0-alpha.9](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.8...6.1.0-alpha.9) (2023-05-09)

### Features

* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d))
2023-05-09 13:04:52 +00:00
alljinx 2caea310be feat: Add option to change the log level of logs emitted by Cloud Functions (#8530) 2023-05-09 15:03:00 +02:00
Lucas Coratger 1302853187 docs: Fix missing logo in API docs (#8528) 2023-05-08 20:43:52 +02:00
Manuel 6207a02df5 ci: Fix CI workflow not running on release branches (#8527) 2023-05-02 00:02:06 +02:00
semantic-release-bot 832702dffd chore(release): 6.1.0 [skip ci]
# [6.1.0](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0) (2023-05-01)

### Bug Fixes

* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))
* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))

### Features

* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))
2023-05-01 21:50:23 +00:00
Manuel 18b63d1da7 build: Release (#8526) 2023-05-01 23:49:22 +02:00
semantic-release-bot f59d46c9e9 chore(release): 6.1.0-beta.2 [skip ci]
# [6.1.0-beta.2](https://github.com/parse-community/parse-server/compare/6.1.0-beta.1...6.1.0-beta.2) (2023-05-01)

### Bug Fixes

* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))

### Features

* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))
2023-05-01 21:36:01 +00:00
Manuel acba5cf16d build: Release beta (#8525) 2023-05-01 23:35:02 +02:00
Manuel 2e4119e23d ci: Fix auto-release outdated ubuntu version (#8524) 2023-05-01 23:16:57 +02:00
semantic-release-bot 2f53c80298 chore(release): 6.1.0-alpha.8 [skip ci]
# [6.1.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.7...6.1.0-alpha.8) (2023-05-01)

### Features

* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
2023-05-01 20:26:26 +00:00
Marc Derhammer 4f15539ac2 feat: Allow multiple origins for header Access-Control-Allow-Origin (#8517) 2023-05-01 22:25:22 +02:00
Lucas Coratger 9e43bc2fa0 docs: Change API docs template to jsdoc-clean-theme (#8519) 2023-04-29 16:53:54 +02:00
Daniel 177891ea0e ci: Fix check definitions CI job not running (#8503) 2023-04-11 09:50:29 +02:00
Daniel 65e5879e42 ci: Fix flaky tests (#8468) 2023-03-10 23:54:05 +01:00
semantic-release-bot cf1b59e97b chore(release): 6.1.0-alpha.7 [skip ci]
# [6.1.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.6...6.1.0-alpha.7) (2023-03-10)

### Bug Fixes

* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))
2023-03-10 16:44:46 +00:00
Daniel d9e347d741 fix: Rate limiting across multiple servers via Redis not working (#8469) 2023-03-10 17:43:37 +01:00
semantic-release-bot c4ce59cbd1 chore(release): 6.1.0-alpha.6 [skip ci]
# [6.1.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.5...6.1.0-alpha.6) (2023-03-06)

### Features

* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
2023-03-06 16:44:46 +00:00
Daniel 34833e42ee feat: Add rate limiting across multiple servers via Redis (#8394) 2023-03-06 17:43:15 +01:00
semantic-release-bot 0f1979f814 chore(release): 6.1.0-alpha.5 [skip ci]
# [6.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.4...6.1.0-alpha.5) (2023-03-06)

### Bug Fixes

* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
2023-03-06 10:27:30 +00:00
Daniel 4ce135a4fe fix: LiveQuery can return incorrectly formatted date (#8456) 2023-03-06 11:26:06 +01:00
semantic-release-bot 6613872ce2 chore(release): 6.1.0-alpha.4 [skip ci]
# [6.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.3...6.1.0-alpha.4) (2023-03-06)

### Bug Fixes

* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
2023-03-06 02:19:01 +00:00
Daniel ce34747e8a fix: Parameters missing in afterFind trigger of authentication adapters (#8458) 2023-03-06 03:18:00 +01:00
semantic-release-bot d05cfcdb95 chore(release): 6.1.0-alpha.3 [skip ci]
# [6.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.2...6.1.0-alpha.3) (2023-03-06)

### Features

* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
2023-03-06 00:36:40 +00:00
Daniel c793bb88e7 feat: Add afterFind trigger to authentication adapters (#8444) 2023-03-06 01:35:15 +01:00
Corey 87cab09b6a refactor: Upgrade pg-promise to 11.3.0 and pg-monitor to 2.0.0 (#8453) 2023-03-06 00:16:04 +01:00
semantic-release-bot 94d558edbb chore(release): 6.1.0-alpha.2 [skip ci]
# [6.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.1...6.1.0-alpha.2) (2023-03-05)

### Bug Fixes

* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
2023-03-05 00:23:27 +00:00
Daniel 22d2446dfe fix: Nested date is incorrectly decoded as empty object {} when fetching a Parse Object (#8446) 2023-03-05 01:22:19 +01:00
semantic-release-bot 3f5b2900a6 chore(release): 6.1.0-alpha.1 [skip ci]
# [6.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-alpha.1) (2023-03-03)

### Bug Fixes

* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))

### Features

* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))
2023-03-03 16:52:51 +00:00
Daniel 40c196153b feat: Export AuthAdapter to make it available for extension with custom authentication adapters (#8443) 2023-03-03 17:51:45 +01:00
semantic-release-bot 656bca6132 chore(release): 6.1.0-beta.1 [skip ci]
# [6.1.0-beta.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-beta.1) (2023-03-02)

### Bug Fixes

* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))

### Features

* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
2023-03-02 10:54:13 +00:00
Manuel 29044aa9c3 build: Release beta (#8452) 2023-03-02 11:53:11 +01:00
Manuel Trezza 33358a6234 Merge branch 'beta' into build 2023-03-02 11:37:47 +01:00
Manuel a74b7c2f74 ci: Remove release-automated-scheduler (#8450) 2023-03-01 17:28:17 +01:00
semantic-release-bot e9ab6b055d chore(release): 6.0.0-alpha.35 [skip ci]
# [6.0.0-alpha.35](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.34...6.0.0-alpha.35) (2023-02-27)

### Features

* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
2023-02-27 00:56:49 +00:00
Daniel b3b76de71b feat: Add option schemaCacheTtl for schema cache pulling as alternative to enableSchemaHooks (#8436) 2023-02-27 01:55:47 +01:00
semantic-release-bot bdca9f4ce3 chore(release): 6.0.0-alpha.34 [skip ci]
# [6.0.0-alpha.34](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.33...6.0.0-alpha.34) (2023-02-24)

### Features

* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
2023-02-24 19:32:10 +00:00
Daniel e5d610e5e4 feat: Add Parse Server option resetPasswordSuccessOnInvalidEmail to choose success or error response on password reset with invalid email (#7551) 2023-02-24 20:30:48 +01:00
semantic-release-bot 5477848518 chore(release): 6.0.0-alpha.33 [skip ci]
# [6.0.0-alpha.33](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.32...6.0.0-alpha.33) (2023-02-17)

### Features

* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
2023-02-17 12:25:43 +00:00
Daniel a49e323d5a feat: Deprecate LiveQuery fields option in favor of keys for semantic consistency (#8388) 2023-02-17 13:24:33 +01:00
dependabot[bot] 992b3c79f5 refactor: Bump cacheable-request and all-node-versions (#8430) 2023-02-13 19:32:46 +01:00
semantic-release-bot e76123b482 chore(release): 6.0.0-alpha.32 [skip ci]
# [6.0.0-alpha.32](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.31...6.0.0-alpha.32) (2023-02-07)

### Bug Fixes

* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))
2023-02-07 11:46:57 +00:00
Daniel f5bfe4571e fix: Security upgrade jsonwebtoken to 9.0.0 (#8420) 2023-02-07 12:45:30 +01:00
Manuel 4450ecbc01 docs: Add issue scope to contribution guide (#8423) 2023-02-04 21:52:28 +01:00
dependabot[bot] 46e2760a46 refactor: Bump http-cache-semantics from 4.1.0 to 4.1.1 (#8422) 2023-02-03 20:08:30 +01:00
semantic-release-bot 8414ad3f32 chore(release): 6.0.0-alpha.31 [skip ci]
# [6.0.0-alpha.31](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.30...6.0.0-alpha.31) (2023-01-31)

### Bug Fixes

* Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) ([#8302](https://github.com/parse-community/parse-server/issues/8302)) ([6728da1](https://github.com/parse-community/parse-server/commit/6728da1e3591db1e27031d335d64d8f25546a06f))
* Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) ([#8305](https://github.com/parse-community/parse-server/issues/8305)) ([60c5a73](https://github.com/parse-community/parse-server/commit/60c5a73d257e0d536056b38bdafef8b7130524d8))
* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) ([#8295](https://github.com/parse-community/parse-server/issues/8295)) ([50eed3c](https://github.com/parse-community/parse-server/commit/50eed3cffe80fadfb4bdac52b2783a18da2cfc4f))
2023-01-31 15:37:19 +00:00
Manuel 70e6914173 ci: Fix CI not running for certain branches (#8417) 2023-01-31 16:35:59 +01:00
semantic-release-bot f7eee19dba chore(release): 6.0.0 [skip ci]
# [6.0.0](https://github.com/parse-community/parse-server/compare/5.4.0...6.0.0) (2023-01-31)

### Bug Fixes

* `ParseServer.verifyServerUrl` may fail if server response headers are missing; remove unnecessary logging ([#8391](https://github.com/parse-community/parse-server/issues/8391)) ([1c37a7c](https://github.com/parse-community/parse-server/commit/1c37a7cd0715949a70b220a629071c7dab7d5e7b))
* Cloud Code trigger `beforeSave` does not work with `Parse.Role` ([#8320](https://github.com/parse-community/parse-server/issues/8320)) ([f29d972](https://github.com/parse-community/parse-server/commit/f29d9720e9b37918fd885c97a31e34c42750e724))
* ES6 modules do not await the import of Cloud Code files ([#8368](https://github.com/parse-community/parse-server/issues/8368)) ([a7bd180](https://github.com/parse-community/parse-server/commit/a7bd180cddd784c8735622f22e012c342ad535fb))
* Nested objects are encoded incorrectly for MongoDB ([#8209](https://github.com/parse-community/parse-server/issues/8209)) ([1412666](https://github.com/parse-community/parse-server/commit/1412666f75829612de6fb9d7ccae35761c9b75cb))
* Parse Server option `masterKeyIps` does not include localhost by default for IPv6 ([#8322](https://github.com/parse-community/parse-server/issues/8322)) ([ab82635](https://github.com/parse-community/parse-server/commit/ab82635b0d4cf323a07ddee51fee587b43dce95c))
* Rate limiter may reject requests that contain a session token ([#8399](https://github.com/parse-community/parse-server/issues/8399)) ([c114dc8](https://github.com/parse-community/parse-server/commit/c114dc8831055d74187b9dfb4c9eeb558520237c))
* Remove Node 12 and Node 17 support ([#8279](https://github.com/parse-community/parse-server/issues/8279)) ([2546cc8](https://github.com/parse-community/parse-server/commit/2546cc8572bea6610cb9b3c7401d9afac0e3c1d6))
* Schema without class level permissions may cause error ([#8409](https://github.com/parse-community/parse-server/issues/8409)) ([aa2cd51](https://github.com/parse-community/parse-server/commit/aa2cd51b703388d925e4572e5c2b2d883c68e49c))
* The client IP address may be determined incorrectly in some cases; this fixes a security vulnerability in which the Parse Server option `masterKeyIps` may be circumvented, see [GHSA-vm5r-c87r-pf6x](https://github.com/parse-community/parse-server/security/advisories/GHSA-vm5r-c87r-pf6x) ([#8372](https://github.com/parse-community/parse-server/issues/8372)) ([892040d](https://github.com/parse-community/parse-server/commit/892040dc2f82a3e2abe2824e4b553521b6f894de))
* Throwing error in Cloud Code Triggers `afterLogin`, `afterLogout` crashes server ([#8280](https://github.com/parse-community/parse-server/issues/8280)) ([130d290](https://github.com/parse-community/parse-server/commit/130d29074e3f763460e5685d0b9059e5a333caff))

### Features

* Access the internal scope of Parse Server using the new `maintenanceKey`; the internal scope contains unofficial and undocumented fields (prefixed with underscore `_`) which are used internally by Parse Server; you may want to manipulate these fields for out-of-band changes such as data migration or correction tasks; changes within the internal scope of Parse Server may happen at any time without notice or changelog entry, it is therefore recommended to look at the source code of Parse Server to understand the effects of manipulating internal fields before using the key; it is discouraged to use the `maintenanceKey` for routine operations in a production environment; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) ([#8212](https://github.com/parse-community/parse-server/issues/8212)) ([f3bcc93](https://github.com/parse-community/parse-server/commit/f3bcc9365cd6f08b0a32c132e8e5ff6d1b650863))
* Adapt `verifyServerUrl` for new asynchronous Parse Server start-up states ([#8366](https://github.com/parse-community/parse-server/issues/8366)) ([ffa4974](https://github.com/parse-community/parse-server/commit/ffa4974158615fbff4a2692b9db41dcb50d3f77b))
* Add `ParseQuery.watch` to trigger LiveQuery only on update of specific fields ([#8028](https://github.com/parse-community/parse-server/issues/8028)) ([fc92faa](https://github.com/parse-community/parse-server/commit/fc92faac75107b3392eeddd916c4c5b45e3c5e0c))
* Add Node 19 support ([#8363](https://github.com/parse-community/parse-server/issues/8363)) ([a4990dc](https://github.com/parse-community/parse-server/commit/a4990dcd29abcb4442f3c424aff482a0a116160f))
* Add option to change the log level of the logs emitted by triggers ([#8328](https://github.com/parse-community/parse-server/issues/8328)) ([8f3b694](https://github.com/parse-community/parse-server/commit/8f3b694e39d4a966567e50dbea4d62e954fa5c06))
* Add request rate limiter based on IP address ([#8174](https://github.com/parse-community/parse-server/issues/8174)) ([6c79f6a](https://github.com/parse-community/parse-server/commit/6c79f6a69e25e47846e3b0685d6bdfd6b91086b1))
* Asynchronous initialization of Parse Server ([#8232](https://github.com/parse-community/parse-server/issues/8232)) ([99fcf45](https://github.com/parse-community/parse-server/commit/99fcf45e55c368de2345b0c4d780e70e0adf0e15))
* Improve authentication adapter interface to support multi-factor authentication (MFA), authentication challenges, and provide a more powerful interface for writing custom authentication adapters ([#8156](https://github.com/parse-community/parse-server/issues/8156)) ([5bbf9ca](https://github.com/parse-community/parse-server/commit/5bbf9cade9a527787fd1002072d4013ab5d8db2b))
* Reduce Docker image size by improving stages ([#8359](https://github.com/parse-community/parse-server/issues/8359)) ([40810b4](https://github.com/parse-community/parse-server/commit/40810b48ebde8b1f21d2448a3a4de0585b1b5e34))
* Remove deprecation `DEPPS1`: Native MongoDB syntax in aggregation pipeline ([#8362](https://github.com/parse-community/parse-server/issues/8362)) ([d0d30c4](https://github.com/parse-community/parse-server/commit/d0d30c4f1394f563724644a8fc81734be538a2c0))
* Remove deprecation `DEPPS2`: Config option `directAccess` defaults to true ([#8284](https://github.com/parse-community/parse-server/issues/8284)) ([f535ee6](https://github.com/parse-community/parse-server/commit/f535ee6ec2abba63f702127258ca49fa5b4e08c9))
* Remove deprecation `DEPPS3`: Config option `enforcePrivateUsers` defaults to `true` ([#8283](https://github.com/parse-community/parse-server/issues/8283)) ([ed499e3](https://github.com/parse-community/parse-server/commit/ed499e32a21bab9a874a9e5367dc71248ce836c4))
* Remove deprecation `DEPPS4`: Remove convenience method for http request `Parse.Cloud.httpRequest`  ([#8287](https://github.com/parse-community/parse-server/issues/8287)) ([2d79c08](https://github.com/parse-community/parse-server/commit/2d79c0835b6a9acaf20d5c943d9b4619bb96831c))
* Remove support for MongoDB 4.0 ([#8292](https://github.com/parse-community/parse-server/issues/8292)) ([37245f6](https://github.com/parse-community/parse-server/commit/37245f62ce83516b6b95a54b850f0274ef680478))
* Restrict use of `masterKey` to localhost by default ([#8281](https://github.com/parse-community/parse-server/issues/8281)) ([6c16021](https://github.com/parse-community/parse-server/commit/6c16021a1f03a70a6d9e68cb64df362d07f3b693))
* Upgrade Node Package Manager lock file `package-lock.json` to version 2 ([#8285](https://github.com/parse-community/parse-server/issues/8285)) ([ee72467](https://github.com/parse-community/parse-server/commit/ee7246733d63e4bda20401f7b00262ff03299f20))
* Upgrade Redis 3 to 4 ([#8293](https://github.com/parse-community/parse-server/issues/8293)) ([7d622f0](https://github.com/parse-community/parse-server/commit/7d622f06a4347e0ad2cba9a4ec07d8d4fb0f67bc))
* Upgrade Redis 3 to 4 for LiveQuery ([#8333](https://github.com/parse-community/parse-server/issues/8333)) ([b2761fb](https://github.com/parse-community/parse-server/commit/b2761fb3786b519d9bbcf35be54309d2d35da1a9))
* Upgrade to Parse JavaScript SDK 4 ([#8332](https://github.com/parse-community/parse-server/issues/8332)) ([9092874](https://github.com/parse-community/parse-server/commit/9092874a9a482a24dfdce1dce56615702999d6b8))
* Write log entry when request with master key is rejected as outside of `masterKeyIps` ([#8350](https://github.com/parse-community/parse-server/issues/8350)) ([e22b73d](https://github.com/parse-community/parse-server/commit/e22b73d4b700c8ff745aa81726c6680082294b45))

### BREAKING CHANGES

* The Docker image does not contain the git dependency anymore; if you have been using git as a transitive dependency it now needs to be explicitly installed in your Docker file, for example with `RUN apk --no-cache add git` (#8359) ([40810b4](40810b4))
* Fields in the internal scope of Parse Server (prefixed with underscore `_`) are only returned using the new `maintenanceKey`; previously the `masterKey` allowed reading of internal fields; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) for a comparison of the keys' access permissions (#8212) ([f3bcc93](f3bcc93))
* The method `ParseServer.verifyServerUrl` now returns a promise instead of a callback. ([ffa4974](ffa4974))
* The MongoDB aggregation pipeline requires native MongoDB syntax instead of the custom Parse Server syntax; for example pipeline stage names require a leading dollar sign like `$match` and the MongoDB document ID is referenced using `_id` instead of `objectId` (#8362) ([d0d30c4](d0d30c4))
* The mechanism to determine the client IP address has been rewritten; to correctly determine the IP address it is now required to set the Parse Server option `trustProxy` accordingly if Parse Server runs behind a proxy server, see the express framework's [trust proxy](https://expressjs.com/en/guide/behind-proxies.html) setting (#8372) ([892040d](892040d))
* The Node Package Manager lock file `package-lock.json` is upgraded to version 2; while it is backwards with version 1 for the npm installer, consider this if you run any non-npm analysis tools that use the lock file (#8285) ([ee72467](ee72467))
* This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232) ([99fcf45](99fcf45))
* Nested objects are now properly stored in the database using JSON serialization; previously, due to a bug only top-level objects were serialized, but nested objects were saved as raw JSON; for example, a nested `Date` object was saved as a JSON object like `{ "__type": "Date", "iso": "2020-01-01T00:00:00.000Z" }` instead of its serialized representation `2020-01-01T00:00:00.000Z` (#8209) ([1412666](1412666))
* The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283) ([ed499e3](ed499e3))
* This release restricts the use of `masterKey` to localhost by default; if you are using Parse Dashboard on a different server to connect to Parse Server you need to add the IP address of the server that hosts Parse Dashboard to this option (#8281) ([6c16021](6c16021))
* This release upgrades to Redis 4; if you are using the Redis cache adapter with Parse Server then this is a breaking change as the Redis client options have changed; see the [Redis migration guide](https://github.com/redis/node-redis/blob/redis%404.0.0/docs/v3-to-v4.md) for more details (#8293) ([7d622f0](7d622f0))
* This release removes support for MongoDB 4.0; the new minimum supported MongoDB version is 4.2. which also removes support for the deprecated MongoDB MMAPv1 storage engine ([37245f6](37245f6))
* Throwing an error in Cloud Code Triggers `afterLogin`, `afterLogout` returns a rejected promise; in previous releases it crashed the server if you did not handle the error on the Node.js process level; consider adapting your code if your app currently handles these errors on the Node.js process level with `process.on('unhandledRejection', ...)` ([130d290](130d290))
* Config option `directAccess` defaults to true; set this to `false` in environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`. ([f535ee6](f535ee6))
* The convenience method for HTTP requests `Parse.Cloud.httpRequest` is removed; use your preferred 3rd party library for making HTTP requests ([2d79c08](2d79c08))
* This release removes Node 12 and Node 17 support ([2546cc8](2546cc8))
2023-01-31 03:36:12 +00:00
Manuel c99adfa771 build: Release (#8415) 2023-01-31 04:35:01 +01:00
semantic-release-bot 301459d216 chore(release): 6.0.0-beta.1 [skip ci]
# [6.0.0-beta.1](https://github.com/parse-community/parse-server/compare/5.4.0...6.0.0-beta.1) (2023-01-31)

### Bug Fixes

* `ParseServer.verifyServerUrl` may fail if server response headers are missing; remove unnecessary logging ([#8391](https://github.com/parse-community/parse-server/issues/8391)) ([1c37a7c](https://github.com/parse-community/parse-server/commit/1c37a7cd0715949a70b220a629071c7dab7d5e7b))
* Cloud Code trigger `beforeSave` does not work with `Parse.Role` ([#8320](https://github.com/parse-community/parse-server/issues/8320)) ([f29d972](https://github.com/parse-community/parse-server/commit/f29d9720e9b37918fd885c97a31e34c42750e724))
* ES6 modules do not await the import of Cloud Code files ([#8368](https://github.com/parse-community/parse-server/issues/8368)) ([a7bd180](https://github.com/parse-community/parse-server/commit/a7bd180cddd784c8735622f22e012c342ad535fb))
* Nested objects are encoded incorrectly for MongoDB ([#8209](https://github.com/parse-community/parse-server/issues/8209)) ([1412666](https://github.com/parse-community/parse-server/commit/1412666f75829612de6fb9d7ccae35761c9b75cb))
* Parse Server option `masterKeyIps` does not include localhost by default for IPv6 ([#8322](https://github.com/parse-community/parse-server/issues/8322)) ([ab82635](https://github.com/parse-community/parse-server/commit/ab82635b0d4cf323a07ddee51fee587b43dce95c))
* Rate limiter may reject requests that contain a session token ([#8399](https://github.com/parse-community/parse-server/issues/8399)) ([c114dc8](https://github.com/parse-community/parse-server/commit/c114dc8831055d74187b9dfb4c9eeb558520237c))
* Remove Node 12 and Node 17 support ([#8279](https://github.com/parse-community/parse-server/issues/8279)) ([2546cc8](https://github.com/parse-community/parse-server/commit/2546cc8572bea6610cb9b3c7401d9afac0e3c1d6))
* Schema without class level permissions may cause error ([#8409](https://github.com/parse-community/parse-server/issues/8409)) ([aa2cd51](https://github.com/parse-community/parse-server/commit/aa2cd51b703388d925e4572e5c2b2d883c68e49c))
* The client IP address may be determined incorrectly in some cases; this fixes a security vulnerability in which the Parse Server option `masterKeyIps` may be circumvented, see [GHSA-vm5r-c87r-pf6x](https://github.com/parse-community/parse-server/security/advisories/GHSA-vm5r-c87r-pf6x) ([#8372](https://github.com/parse-community/parse-server/issues/8372)) ([892040d](https://github.com/parse-community/parse-server/commit/892040dc2f82a3e2abe2824e4b553521b6f894de))
* Throwing error in Cloud Code Triggers `afterLogin`, `afterLogout` crashes server ([#8280](https://github.com/parse-community/parse-server/issues/8280)) ([130d290](https://github.com/parse-community/parse-server/commit/130d29074e3f763460e5685d0b9059e5a333caff))

### Features

* Access the internal scope of Parse Server using the new `maintenanceKey`; the internal scope contains unofficial and undocumented fields (prefixed with underscore `_`) which are used internally by Parse Server; you may want to manipulate these fields for out-of-band changes such as data migration or correction tasks; changes within the internal scope of Parse Server may happen at any time without notice or changelog entry, it is therefore recommended to look at the source code of Parse Server to understand the effects of manipulating internal fields before using the key; it is discouraged to use the `maintenanceKey` for routine operations in a production environment; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) ([#8212](https://github.com/parse-community/parse-server/issues/8212)) ([f3bcc93](https://github.com/parse-community/parse-server/commit/f3bcc9365cd6f08b0a32c132e8e5ff6d1b650863))
* Adapt `verifyServerUrl` for new asynchronous Parse Server start-up states ([#8366](https://github.com/parse-community/parse-server/issues/8366)) ([ffa4974](https://github.com/parse-community/parse-server/commit/ffa4974158615fbff4a2692b9db41dcb50d3f77b))
* Add `ParseQuery.watch` to trigger LiveQuery only on update of specific fields ([#8028](https://github.com/parse-community/parse-server/issues/8028)) ([fc92faa](https://github.com/parse-community/parse-server/commit/fc92faac75107b3392eeddd916c4c5b45e3c5e0c))
* Add Node 19 support ([#8363](https://github.com/parse-community/parse-server/issues/8363)) ([a4990dc](https://github.com/parse-community/parse-server/commit/a4990dcd29abcb4442f3c424aff482a0a116160f))
* Add option to change the log level of the logs emitted by triggers ([#8328](https://github.com/parse-community/parse-server/issues/8328)) ([8f3b694](https://github.com/parse-community/parse-server/commit/8f3b694e39d4a966567e50dbea4d62e954fa5c06))
* Add request rate limiter based on IP address ([#8174](https://github.com/parse-community/parse-server/issues/8174)) ([6c79f6a](https://github.com/parse-community/parse-server/commit/6c79f6a69e25e47846e3b0685d6bdfd6b91086b1))
* Asynchronous initialization of Parse Server ([#8232](https://github.com/parse-community/parse-server/issues/8232)) ([99fcf45](https://github.com/parse-community/parse-server/commit/99fcf45e55c368de2345b0c4d780e70e0adf0e15))
* Improve authentication adapter interface to support multi-factor authentication (MFA), authentication challenges, and provide a more powerful interface for writing custom authentication adapters ([#8156](https://github.com/parse-community/parse-server/issues/8156)) ([5bbf9ca](https://github.com/parse-community/parse-server/commit/5bbf9cade9a527787fd1002072d4013ab5d8db2b))
* Reduce Docker image size by improving stages ([#8359](https://github.com/parse-community/parse-server/issues/8359)) ([40810b4](https://github.com/parse-community/parse-server/commit/40810b48ebde8b1f21d2448a3a4de0585b1b5e34))
* Remove deprecation `DEPPS1`: Native MongoDB syntax in aggregation pipeline ([#8362](https://github.com/parse-community/parse-server/issues/8362)) ([d0d30c4](https://github.com/parse-community/parse-server/commit/d0d30c4f1394f563724644a8fc81734be538a2c0))
* Remove deprecation `DEPPS2`: Config option `directAccess` defaults to true ([#8284](https://github.com/parse-community/parse-server/issues/8284)) ([f535ee6](https://github.com/parse-community/parse-server/commit/f535ee6ec2abba63f702127258ca49fa5b4e08c9))
* Remove deprecation `DEPPS3`: Config option `enforcePrivateUsers` defaults to `true` ([#8283](https://github.com/parse-community/parse-server/issues/8283)) ([ed499e3](https://github.com/parse-community/parse-server/commit/ed499e32a21bab9a874a9e5367dc71248ce836c4))
* Remove deprecation `DEPPS4`: Remove convenience method for http request `Parse.Cloud.httpRequest`  ([#8287](https://github.com/parse-community/parse-server/issues/8287)) ([2d79c08](https://github.com/parse-community/parse-server/commit/2d79c0835b6a9acaf20d5c943d9b4619bb96831c))
* Remove support for MongoDB 4.0 ([#8292](https://github.com/parse-community/parse-server/issues/8292)) ([37245f6](https://github.com/parse-community/parse-server/commit/37245f62ce83516b6b95a54b850f0274ef680478))
* Restrict use of `masterKey` to localhost by default ([#8281](https://github.com/parse-community/parse-server/issues/8281)) ([6c16021](https://github.com/parse-community/parse-server/commit/6c16021a1f03a70a6d9e68cb64df362d07f3b693))
* Upgrade Node Package Manager lock file `package-lock.json` to version 2 ([#8285](https://github.com/parse-community/parse-server/issues/8285)) ([ee72467](https://github.com/parse-community/parse-server/commit/ee7246733d63e4bda20401f7b00262ff03299f20))
* Upgrade Redis 3 to 4 ([#8293](https://github.com/parse-community/parse-server/issues/8293)) ([7d622f0](https://github.com/parse-community/parse-server/commit/7d622f06a4347e0ad2cba9a4ec07d8d4fb0f67bc))
* Upgrade Redis 3 to 4 for LiveQuery ([#8333](https://github.com/parse-community/parse-server/issues/8333)) ([b2761fb](https://github.com/parse-community/parse-server/commit/b2761fb3786b519d9bbcf35be54309d2d35da1a9))
* Upgrade to Parse JavaScript SDK 4 ([#8332](https://github.com/parse-community/parse-server/issues/8332)) ([9092874](https://github.com/parse-community/parse-server/commit/9092874a9a482a24dfdce1dce56615702999d6b8))
* Write log entry when request with master key is rejected as outside of `masterKeyIps` ([#8350](https://github.com/parse-community/parse-server/issues/8350)) ([e22b73d](https://github.com/parse-community/parse-server/commit/e22b73d4b700c8ff745aa81726c6680082294b45))

### BREAKING CHANGES

* The Docker image does not contain the git dependency anymore; if you have been using git as a transitive dependency it now needs to be explicitly installed in your Docker file, for example with `RUN apk --no-cache add git` (#8359) ([40810b4](40810b4))
* Fields in the internal scope of Parse Server (prefixed with underscore `_`) are only returned using the new `maintenanceKey`; previously the `masterKey` allowed reading of internal fields; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) for a comparison of the keys' access permissions (#8212) ([f3bcc93](f3bcc93))
* The method `ParseServer.verifyServerUrl` now returns a promise instead of a callback. ([ffa4974](ffa4974))
* The MongoDB aggregation pipeline requires native MongoDB syntax instead of the custom Parse Server syntax; for example pipeline stage names require a leading dollar sign like `$match` and the MongoDB document ID is referenced using `_id` instead of `objectId` (#8362) ([d0d30c4](d0d30c4))
* The mechanism to determine the client IP address has been rewritten; to correctly determine the IP address it is now required to set the Parse Server option `trustProxy` accordingly if Parse Server runs behind a proxy server, see the express framework's [trust proxy](https://expressjs.com/en/guide/behind-proxies.html) setting (#8372) ([892040d](892040d))
* The Node Package Manager lock file `package-lock.json` is upgraded to version 2; while it is backwards with version 1 for the npm installer, consider this if you run any non-npm analysis tools that use the lock file (#8285) ([ee72467](ee72467))
* This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232) ([99fcf45](99fcf45))
* Nested objects are now properly stored in the database using JSON serialization; previously, due to a bug only top-level objects were serialized, but nested objects were saved as raw JSON; for example, a nested `Date` object was saved as a JSON object like `{ "__type": "Date", "iso": "2020-01-01T00:00:00.000Z" }` instead of its serialized representation `2020-01-01T00:00:00.000Z` (#8209) ([1412666](1412666))
* The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283) ([ed499e3](ed499e3))
* This release restricts the use of `masterKey` to localhost by default; if you are using Parse Dashboard on a different server to connect to Parse Server you need to add the IP address of the server that hosts Parse Dashboard to this option (#8281) ([6c16021](6c16021))
* This release upgrades to Redis 4; if you are using the Redis cache adapter with Parse Server then this is a breaking change as the Redis client options have changed; see the [Redis migration guide](https://github.com/redis/node-redis/blob/redis%404.0.0/docs/v3-to-v4.md) for more details (#8293) ([7d622f0](7d622f0))
* This release removes support for MongoDB 4.0; the new minimum supported MongoDB version is 4.2. which also removes support for the deprecated MongoDB MMAPv1 storage engine ([37245f6](37245f6))
* Throwing an error in Cloud Code Triggers `afterLogin`, `afterLogout` returns a rejected promise; in previous releases it crashed the server if you did not handle the error on the Node.js process level; consider adapting your code if your app currently handles these errors on the Node.js process level with `process.on('unhandledRejection', ...)` ([130d290](130d290))
* Config option `directAccess` defaults to true; set this to `false` in environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`. ([f535ee6](f535ee6))
* The convenience method for HTTP requests `Parse.Cloud.httpRequest` is removed; use your preferred 3rd party library for making HTTP requests ([2d79c08](2d79c08))
* This release removes Node 12 and Node 17 support ([2546cc8](2546cc8))
2023-01-31 03:18:06 +00:00
Manuel 7a0949cf79 build: Release beta (#8414) 2023-01-31 04:17:06 +01:00
Manuel Trezza 39a074fd0e Merge branch 'beta' into build-release-beta
* beta:
  docs: remove "skip release" entries from changelog
  chore(release): 5.4.0 [skip ci]
  refactor: Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) (#8307)
  chore(release): 5.3.3 [skip ci]
  fix: Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) (#8305)
  chore(release): 5.3.2 [skip ci]
  refactor: Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) (#8303)
  fix: Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) (#8302)
  refactor: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) (#8298)
  chore(release): 5.3.1 [skip ci]
  fix: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) (#8295)
2023-01-31 04:11:52 +01:00
Manuel ab181ad1d6 refactor: Upgrade to latest Parse JS SDK dependency (#8413) 2023-01-31 04:04:49 +01:00
Manuel 9ed42d7fb5 docs: Consolidate LICENSE and PATENTS clauses into Apache 2.0 (#8408) 2023-01-31 01:02:05 +01:00
semantic-release-bot 8b97988f0d chore(release): 6.0.0-alpha.30 [skip ci]
# [6.0.0-alpha.30](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.29...6.0.0-alpha.30) (2023-01-27)

### Bug Fixes

* Schema without class level permissions may cause error ([#8409](https://github.com/parse-community/parse-server/issues/8409)) ([aa2cd51](https://github.com/parse-community/parse-server/commit/aa2cd51b703388d925e4572e5c2b2d883c68e49c))
2023-01-27 16:59:14 +00:00
Diamond Lewis aa2cd51b70 fix: Schema without class level permissions may cause error (#8409) 2023-01-27 17:57:50 +01:00
Manuel cf6966fa10 docs: Update README LTS references (#8407) 2023-01-26 15:00:28 +01:00
semantic-release-bot fe2b5e4b7c chore(release): 6.0.0-alpha.29 [skip ci]
# [6.0.0-alpha.29](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.28...6.0.0-alpha.29) (2023-01-26)

### Features

* Upgrade to Parse JavaScript SDK 4 ([#8332](https://github.com/parse-community/parse-server/issues/8332)) ([9092874](https://github.com/parse-community/parse-server/commit/9092874a9a482a24dfdce1dce56615702999d6b8))
2023-01-26 09:50:08 +00:00
Daniel 9092874a9a feat: Upgrade to Parse JavaScript SDK 4 (#8332) 2023-01-26 10:49:03 +01:00
semantic-release-bot 8adc054592 chore(release): 6.0.0-alpha.28 [skip ci]
# [6.0.0-alpha.28](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.27...6.0.0-alpha.28) (2023-01-25)

### Bug Fixes

* Rate limiter may reject requests that contain a session token ([#8399](https://github.com/parse-community/parse-server/issues/8399)) ([c114dc8](https://github.com/parse-community/parse-server/commit/c114dc8831055d74187b9dfb4c9eeb558520237c))
2023-01-25 13:36:46 +00:00
Daniel c114dc8831 fix: Rate limiter may reject requests that contain a session token (#8399) 2023-01-25 14:35:39 +01:00
Manuel 8f7a8f4c9d docs: Remove migration docs of outdated versions (#8403) 2023-01-24 19:33:55 +01:00
semantic-release-bot f7f5e7e203 chore(release): 6.0.0-alpha.27 [skip ci]
# [6.0.0-alpha.27](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.26...6.0.0-alpha.27) (2023-01-23)

### Bug Fixes

* `ParseServer.verifyServerUrl` may fail if server response headers are missing; remove unnecessary logging ([#8391](https://github.com/parse-community/parse-server/issues/8391)) ([1c37a7c](https://github.com/parse-community/parse-server/commit/1c37a7cd0715949a70b220a629071c7dab7d5e7b))
2023-01-23 19:41:07 +00:00
Daniel 1c37a7cd07 fix: ParseServer.verifyServerUrl may fail if server response headers are missing; remove unnecessary logging (#8391) 2023-01-23 20:39:48 +01:00
semantic-release-bot 5a35e6ff0d chore(release): 6.0.0-alpha.26 [skip ci]
# [6.0.0-alpha.26](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.25...6.0.0-alpha.26) (2023-01-20)

### Bug Fixes

* ES6 modules do not await the import of Cloud Code files ([#8368](https://github.com/parse-community/parse-server/issues/8368)) ([a7bd180](https://github.com/parse-community/parse-server/commit/a7bd180cddd784c8735622f22e012c342ad535fb))
2023-01-20 15:41:26 +00:00
Daniel a7bd180cdd fix: ES6 modules do not await the import of Cloud Code files (#8368) 2023-01-20 16:40:09 +01:00
semantic-release-bot eb0311b570 chore(release): 6.0.0-alpha.25 [skip ci]
# [6.0.0-alpha.25](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.24...6.0.0-alpha.25) (2023-01-16)

### Features

* Add `ParseQuery.watch` to trigger LiveQuery only on update of specific fields ([#8028](https://github.com/parse-community/parse-server/issues/8028)) ([fc92faa](https://github.com/parse-community/parse-server/commit/fc92faac75107b3392eeddd916c4c5b45e3c5e0c))
2023-01-16 11:33:27 +00:00
Daniel fc92faac75 feat: Add ParseQuery.watch to trigger LiveQuery only on update of specific fields (#8028) 2023-01-16 12:32:22 +01:00
semantic-release-bot 62b3426b14 chore(release): 6.0.0-alpha.24 [skip ci]
# [6.0.0-alpha.24](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.23...6.0.0-alpha.24) (2023-01-09)

### Features

* Reduce Docker image size by improving stages ([#8359](https://github.com/parse-community/parse-server/issues/8359)) ([40810b4](https://github.com/parse-community/parse-server/commit/40810b48ebde8b1f21d2448a3a4de0585b1b5e34))

### BREAKING CHANGES

* The Docker image does not contain the git dependency anymore; if you have been using git as a transitive dependency it now needs to be explicitly installed in your Docker file, for example with `RUN apk --no-cache add git` (#8359) ([40810b4](40810b4))
2023-01-09 18:27:16 +00:00
Corey 40810b48eb feat: Reduce Docker image size by improving stages (#8359)
BREAKING CHANGE: The Docker image does not contain the git dependency anymore; if you have been using git as a transitive dependency it now needs to be explicitly installed in your Docker file, for example with `RUN apk --no-cache add git` (#8359)
2023-01-09 18:26:03 +00:00
Manuel bd82d8ede1 ci: Fix Node 14 git protocol in workflow (#8381) 2023-01-09 09:54:11 +01:00
semantic-release-bot 9d461df0c0 chore(release): 6.0.0-alpha.23 [skip ci]
# [6.0.0-alpha.23](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.22...6.0.0-alpha.23) (2023-01-08)

### Features

* Access the internal scope of Parse Server using the new `maintenanceKey`; the internal scope contains unofficial and undocumented fields (prefixed with underscore `_`) which are used internally by Parse Server; you may want to manipulate these fields for out-of-band changes such as data migration or correction tasks; changes within the internal scope of Parse Server may happen at any time without notice or changelog entry, it is therefore recommended to look at the source code of Parse Server to understand the effects of manipulating internal fields before using the key; it is discouraged to use the `maintenanceKey` for routine operations in a production environment; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) ([#8212](https://github.com/parse-community/parse-server/issues/8212)) ([f3bcc93](https://github.com/parse-community/parse-server/commit/f3bcc9365cd6f08b0a32c132e8e5ff6d1b650863))

### BREAKING CHANGES

* Fields in the internal scope of Parse Server (prefixed with underscore `_`) are only returned using the new `maintenanceKey`; previously the `masterKey` allowed reading of internal fields; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) for a comparison of the keys' access permissions (#8212) ([f3bcc93](f3bcc93))
2023-01-08 21:04:17 +00:00
Daniel f3bcc9365c feat: Access the internal scope of Parse Server using the new maintenanceKey; the internal scope contains unofficial and undocumented fields (prefixed with underscore _) which are used internally by Parse Server; you may want to manipulate these fields for out-of-band changes such as data migration or correction tasks; changes within the internal scope of Parse Server may happen at any time without notice or changelog entry, it is therefore recommended to look at the source code of Parse Server to understand the effects of manipulating internal fields before using the key; it is discouraged to use the maintenanceKey for routine operations in a production environment; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) (#8212)
BREAKING CHANGE: Fields in the internal scope of Parse Server (prefixed with underscore `_`) are only returned using the new `maintenanceKey`; previously the `masterKey` allowed reading of internal fields; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) for a comparison of the keys' access permissions (#8212)
2023-01-08 22:02:12 +01:00
semantic-release-bot 3d57072c1f chore(release): 6.0.0-alpha.22 [skip ci]
# [6.0.0-alpha.22](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.21...6.0.0-alpha.22) (2023-01-08)

### Features

* Adapt `verifyServerUrl` for new asynchronous Parse Server start-up states ([#8366](https://github.com/parse-community/parse-server/issues/8366)) ([ffa4974](https://github.com/parse-community/parse-server/commit/ffa4974158615fbff4a2692b9db41dcb50d3f77b))

### BREAKING CHANGES

* The method `ParseServer.verifyServerUrl` now returns a promise instead of a callback. ([ffa4974](ffa4974))
2023-01-08 17:23:57 +00:00
Daniel ffa4974158 feat: Adapt verifyServerUrl for new asynchronous Parse Server start-up states (#8366)
BREAKING CHANGE: The method `ParseServer.verifyServerUrl` now returns a promise instead of a callback.
2023-01-08 18:23:01 +01:00
semantic-release-bot 76c7a6fbd0 chore(release): 6.0.0-alpha.21 [skip ci]
# [6.0.0-alpha.21](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.20...6.0.0-alpha.21) (2023-01-06)

### Features

* Add request rate limiter based on IP address ([#8174](https://github.com/parse-community/parse-server/issues/8174)) ([6c79f6a](https://github.com/parse-community/parse-server/commit/6c79f6a69e25e47846e3b0685d6bdfd6b91086b1))
2023-01-06 12:40:11 +00:00
Daniel 6c79f6a69e feat: Add request rate limiter based on IP address (#8174) 2023-01-06 13:39:02 +01:00
semantic-release-bot 0eac5dc6d4 chore(release): 6.0.0-alpha.20 [skip ci]
# [6.0.0-alpha.20](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.19...6.0.0-alpha.20) (2023-01-06)

### Features

* Add Node 19 support ([#8363](https://github.com/parse-community/parse-server/issues/8363)) ([a4990dc](https://github.com/parse-community/parse-server/commit/a4990dcd29abcb4442f3c424aff482a0a116160f))
2023-01-06 11:38:20 +00:00
Daniel a4990dcd29 feat: Add Node 19 support (#8363) 2023-01-06 12:37:07 +01:00
dependabot[bot] b1bb1fcfeb refactor: Bump json5 from 1.0.1 to 1.0.2 (#8373) 2023-01-05 16:57:36 +01:00
semantic-release-bot 8895fbb82b chore(release): 6.0.0-alpha.19 [skip ci]
# [6.0.0-alpha.19](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.18...6.0.0-alpha.19) (2023-01-05)

### Features

* Remove deprecation `DEPPS1`: Native MongoDB syntax in aggregation pipeline ([#8362](https://github.com/parse-community/parse-server/issues/8362)) ([d0d30c4](https://github.com/parse-community/parse-server/commit/d0d30c4f1394f563724644a8fc81734be538a2c0))

### BREAKING CHANGES

* The MongoDB aggregation pipeline requires native MongoDB syntax instead of the custom Parse Server syntax; for example pipeline stage names require a leading dollar sign like `$match` and the MongoDB document ID is referenced using `_id` instead of `objectId` (#8362) ([d0d30c4](d0d30c4))
2023-01-05 14:54:53 +00:00
Daniel d0d30c4f13 feat: Remove deprecation DEPPS1: Native MongoDB syntax in aggregation pipeline (#8362)
BREAKING CHANGE: The MongoDB aggregation pipeline requires native MongoDB syntax instead of the custom Parse Server syntax; for example pipeline stage names require a leading dollar sign like `$match` and the MongoDB document ID is referenced using `_id` instead of `objectId` (#8362)
2023-01-05 15:53:43 +01:00
semantic-release-bot df00cbebe3 chore(release): 6.0.0-alpha.18 [skip ci]
# [6.0.0-alpha.18](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.17...6.0.0-alpha.18) (2023-01-05)

### Bug Fixes

* The client IP address may be determined incorrectly in some cases; this fixes a security vulnerability in which the Parse Server option `masterKeyIps` may be circumvented, see [GHSA-vm5r-c87r-pf6x](https://github.com/parse-community/parse-server/security/advisories/GHSA-vm5r-c87r-pf6x) ([#8372](https://github.com/parse-community/parse-server/issues/8372)) ([892040d](https://github.com/parse-community/parse-server/commit/892040dc2f82a3e2abe2824e4b553521b6f894de))

### BREAKING CHANGES

* The mechanism to determine the client IP address has been rewritten; to correctly determine the IP address it is now required to set the Parse Server option `trustProxy` accordingly if Parse Server runs behind a proxy server, see the express framework's [trust proxy](https://expressjs.com/en/guide/behind-proxies.html) setting (#8372) ([892040d](892040d))
2023-01-05 13:34:56 +00:00
Manuel 892040dc2f fix: The client IP address may be determined incorrectly in some cases; this fixes a security vulnerability in which the Parse Server option masterKeyIps may be circumvented, see [GHSA-vm5r-c87r-pf6x](https://github.com/parse-community/parse-server/security/advisories/GHSA-vm5r-c87r-pf6x) (#8372)
BREAKING CHANGE: The mechanism to determine the client IP address has been rewritten; to correctly determine the IP address it is now required to set the Parse Server option `trustProxy` accordingly if Parse Server runs behind a proxy server, see the express framework's [trust proxy](https://expressjs.com/en/guide/behind-proxies.html) setting (#8372)
2023-01-05 14:26:54 +01:00
Manuel b7815ed80a ci: Add LTS branches to CI workflow 2023-01-05 13:21:44 +01:00
semantic-release-bot d19acf1c1a chore(release): 6.0.0-alpha.17 [skip ci]
# [6.0.0-alpha.17](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.16...6.0.0-alpha.17) (2022-12-22)

### Features

* Upgrade Node Package Manager lock file `package-lock.json` to version 2 ([#8285](https://github.com/parse-community/parse-server/issues/8285)) ([ee72467](https://github.com/parse-community/parse-server/commit/ee7246733d63e4bda20401f7b00262ff03299f20))

### BREAKING CHANGES

* The Node Package Manager lock file `package-lock.json` is upgraded to version 2; while it is backwards with version 1 for the npm installer, consider this if you run any non-npm analysis tools that use the lock file (#8285) ([ee72467](ee72467))
2022-12-22 12:27:46 +00:00
Daniel ee7246733d feat: Upgrade Node Package Manager lock file package-lock.json to version 2 (#8285)
BREAKING CHANGE: The Node Package Manager lock file `package-lock.json` is upgraded to version 2; while it is backwards with version 1 for the npm installer, consider this if you run any non-npm analysis tools that use the lock file (#8285)
2022-12-22 13:26:38 +01:00
semantic-release-bot 49388df693 chore(release): 6.0.0-alpha.16 [skip ci]
# [6.0.0-alpha.16](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.15...6.0.0-alpha.16) (2022-12-21)

### Features

* Asynchronous initialization of Parse Server ([#8232](https://github.com/parse-community/parse-server/issues/8232)) ([99fcf45](https://github.com/parse-community/parse-server/commit/99fcf45e55c368de2345b0c4d780e70e0adf0e15))

### BREAKING CHANGES

* This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232) ([99fcf45](99fcf45))
2022-12-21 14:31:54 +00:00
Daniel 99fcf45e55 feat: Asynchronous initialization of Parse Server (#8232)
BREAKING CHANGE: This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232)
2022-12-21 15:30:13 +01:00
semantic-release-bot db9941c5a6 chore(release): 6.0.0-alpha.15 [skip ci]
# [6.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.14...6.0.0-alpha.15) (2022-12-20)

### Bug Fixes

* Nested objects are encoded incorrectly for MongoDB ([#8209](https://github.com/parse-community/parse-server/issues/8209)) ([1412666](https://github.com/parse-community/parse-server/commit/1412666f75829612de6fb9d7ccae35761c9b75cb))

### BREAKING CHANGES

* Nested objects are now properly stored in the database using JSON serialization; previously, due to a bug only top-level objects were serialized, but nested objects were saved as raw JSON; for example, a nested `Date` object was saved as a JSON object like `{ "__type": "Date", "iso": "2020-01-01T00:00:00.000Z" }` instead of its serialized representation `2020-01-01T00:00:00.000Z` (#8209) ([1412666](1412666))
2022-12-20 15:59:16 +00:00
Daniel 1412666f75 fix: Nested objects are encoded incorrectly for MongoDB (#8209)
BREAKING CHANGE: Nested objects are now properly stored in the database using JSON serialization; previously, due to a bug only top-level objects were serialized, but nested objects were saved as raw JSON; for example, a nested `Date` object was saved as a JSON object like `{ "__type": "Date", "iso": "2020-01-01T00:00:00.000Z" }` instead of its serialized representation `2020-01-01T00:00:00.000Z` (#8209)
2022-12-20 16:57:29 +01:00
Manuel 6323368d3f docs: fix typo in CONTRIBUTING 2022-12-17 20:31:00 +01:00
Manuel 65c2d2ced2 docs: add vulnerability merging to CONTRIBUTING.md 2022-12-17 20:26:53 +01:00
Daniel 5a26426f23 ci: Add CI check for Parse Server options definitions (#7955) 2022-12-17 13:15:23 +01:00
semantic-release-bot 65a6dd180e chore(release): 6.0.0-alpha.14 [skip ci]
# [6.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.13...6.0.0-alpha.14) (2022-12-16)

### Features

* Write log entry when request with master key is rejected as outside of `masterKeyIps` ([#8350](https://github.com/parse-community/parse-server/issues/8350)) ([e22b73d](https://github.com/parse-community/parse-server/commit/e22b73d4b700c8ff745aa81726c6680082294b45))
2022-12-16 02:45:55 +00:00
Daniel e22b73d4b7 feat: Write log entry when request with master key is rejected as outside of masterKeyIps (#8350) 2022-12-16 03:43:50 +01:00
Manuel 679c61db63 docs: remove "skip release" entries from changelog 2022-12-14 18:28:32 +01:00
semantic-release-bot fded5be186 chore(release): 6.0.0-alpha.13 [skip ci]
# [6.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.12...6.0.0-alpha.13) (2022-12-07)

### Features

* Add option to change the log level of the logs emitted by triggers ([#8328](https://github.com/parse-community/parse-server/issues/8328)) ([8f3b694](https://github.com/parse-community/parse-server/commit/8f3b694e39d4a966567e50dbea4d62e954fa5c06))
2022-12-07 21:57:21 +00:00
alljinx 8f3b694e39 feat: Add option to change the log level of the logs emitted by triggers (#8328) 2022-12-07 22:55:45 +01:00
dependabot[bot] 0a8670dc22 refactor: Bump qs from 6.5.2 to 6.5.3 (#8348) 2022-12-07 16:31:54 +01:00
Manuel b48c27049a refactor: Improve incorrect deprecation log message for auth adapter (#8347) 2022-12-06 23:04:37 +01:00
dependabot[bot] 536bb2f1ae refactor: Bump decode-uri-component from 0.2.0 to 0.2.2 (#8342) 2022-12-06 16:16:18 +01:00
semantic-release-bot b458dcec91 chore(release): 6.0.0-alpha.12 [skip ci]
# [6.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.11...6.0.0-alpha.12) (2022-11-26)

### Features

* Upgrade Redis 3 to 4 for LiveQuery ([#8333](https://github.com/parse-community/parse-server/issues/8333)) ([b2761fb](https://github.com/parse-community/parse-server/commit/b2761fb3786b519d9bbcf35be54309d2d35da1a9))
2022-11-26 16:47:14 +00:00
Daniel b2761fb378 feat: Upgrade Redis 3 to 4 for LiveQuery (#8333) 2022-11-26 17:45:30 +01:00
dependabot[bot] 40dd82ff19 refactor: Bump minimatch from 3.0.4 to 3.1.2 (#8336) 2022-11-26 00:57:07 +01:00
semantic-release-bot e32cc7db93 chore(release): 6.0.0-alpha.11 [skip ci]
# [6.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.10...6.0.0-alpha.11) (2022-11-25)

### Bug Fixes

* Parse Server option `masterKeyIps` does not include localhost by default for IPv6 ([#8322](https://github.com/parse-community/parse-server/issues/8322)) ([ab82635](https://github.com/parse-community/parse-server/commit/ab82635b0d4cf323a07ddee51fee587b43dce95c))
2022-11-25 22:21:11 +00:00
Daniel ab82635b0d fix: Parse Server option masterKeyIps does not include localhost by default for IPv6 (#8322) 2022-11-25 23:19:14 +01:00
Manuel 6f527440c2 ci: Update release workflow for LTS branches (#8327) 2022-11-19 17:44:01 +01:00
Manuel c312e261b6 ci: Add auto-release LTS branch detection (#8326) 2022-11-19 17:37:15 +01:00
Manuel fe3dc0d14d ci: Add auto-release LTS branch detection (#8325) 2022-11-19 17:09:42 +01:00
semantic-release-bot 9b34b0263b chore(release): 5.4.0 [skip ci]
# [5.4.0](https://github.com/parse-community/parse-server/compare/5.3.3...5.4.0) (2022-11-19)

### Bug Fixes

* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] ([#8187](https://github.com/parse-community/parse-server/issues/8187)) ([8c8ec71](https://github.com/parse-community/parse-server/commit/8c8ec715739e0f851338cfed794409ebac66c51b))
* brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) ([#8146](https://github.com/parse-community/parse-server/issues/8146)) [skip release] ([4c0c7c7](https://github.com/parse-community/parse-server/commit/4c0c7c77b76257878b9bcb05ff9de01c9d790262))
* certificate in Apple Game Center auth adapter not validated [skip release] ([#8058](https://github.com/parse-community/parse-server/issues/8058)) ([75af9a2](https://github.com/parse-community/parse-server/commit/75af9a26cc8e9e88a33d1e452c93a0ee6e509f17))
* graphQL query ignores condition `equalTo` with value `false` ([#8032](https://github.com/parse-community/parse-server/issues/8032)) ([7f5a15d](https://github.com/parse-community/parse-server/commit/7f5a15d5df0dfa3515e9f73709d6a49663545f9b))
* internal indices for classes `_Idempotency` and `_Role` are not protected in defined schema ([#8121](https://github.com/parse-community/parse-server/issues/8121)) ([c16f529](https://github.com/parse-community/parse-server/commit/c16f529f74f92154401bf662f634b3c5fa45e18e))
* invalid file request not properly handled [skip release] ([#8062](https://github.com/parse-community/parse-server/issues/8062)) ([4c9e956](https://github.com/parse-community/parse-server/commit/4c9e95674ad081f13062e8cd30b77b1962d5df57))
* liveQuery with `containedIn` not working when object field is an array ([#8128](https://github.com/parse-community/parse-server/issues/8128)) ([1d9605b](https://github.com/parse-community/parse-server/commit/1d9605bc93009263d3811df4d4249034ba6eb8c4))
* protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] ([#8076](https://github.com/parse-community/parse-server/issues/8076)) ([9fd4516](https://github.com/parse-community/parse-server/commit/9fd4516cde5c742f9f29dd05468b4a43a85639a6))
* push notifications `badge` doesn't update with Installation beforeSave trigger ([#8162](https://github.com/parse-community/parse-server/issues/8162)) ([3c75c2b](https://github.com/parse-community/parse-server/commit/3c75c2ba4851fae96a8c19b11a3efde03816c9a1))
* query aggregation pipeline cannot handle value of type `Date` when `directAccess: true` ([#8167](https://github.com/parse-community/parse-server/issues/8167)) ([e424137](https://github.com/parse-community/parse-server/commit/e4241374061caef66538de15112fb6bbafb1f5bb))
* relation constraints in compound queries `Parse.Query.or`, `Parse.Query.and` not working ([#8203](https://github.com/parse-community/parse-server/issues/8203)) ([28f0d26](https://github.com/parse-community/parse-server/commit/28f0d2667787d2ac68726607b811d6f0ef62b9f1))
* security upgrade undici from 5.6.0 to 5.8.0 ([#8108](https://github.com/parse-community/parse-server/issues/8108)) ([4aa016b](https://github.com/parse-community/parse-server/commit/4aa016b7322467422b9fdf05d8e29b9ecf910da7))
* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] ([#8238](https://github.com/parse-community/parse-server/issues/8238)) ([c03908f](https://github.com/parse-community/parse-server/commit/c03908f74e5c9eed834874a89df6c89c1a1e849f))
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] ([#8180](https://github.com/parse-community/parse-server/issues/8180)) ([37fed30](https://github.com/parse-community/parse-server/commit/37fed3062ccc3ef1dfd49a9fc53318e72b3e4aff))
* sorting by non-existing value throws `INVALID_SERVER_ERROR` on Postgres ([#8157](https://github.com/parse-community/parse-server/issues/8157)) ([3b775a1](https://github.com/parse-community/parse-server/commit/3b775a1fb8a1878714e3451191438963d688f1b0))
* updating object includes unchanged keys in client response for certain key types ([#8159](https://github.com/parse-community/parse-server/issues/8159)) ([37af1d7](https://github.com/parse-community/parse-server/commit/37af1d78fce5a15039ffe3af7b323c1f1e8582fc))

### Features

* add convenience access to Parse Server configuration in Cloud Code via `Parse.Server` ([#8244](https://github.com/parse-community/parse-server/issues/8244)) ([9f11115](https://github.com/parse-community/parse-server/commit/9f111158edf7fd57a65db0c4f9244b37e58cf293))
* add option to change the default value of the `Parse.Query.limit()` constraint ([#8152](https://github.com/parse-community/parse-server/issues/8152)) ([0388956](https://github.com/parse-community/parse-server/commit/038895680894984e569dff54bf5c7b31094f3891))
* add support for MongoDB 6 ([#8242](https://github.com/parse-community/parse-server/issues/8242)) ([aba0081](https://github.com/parse-community/parse-server/commit/aba0081ce1a166a93de57f3928c19a05562b5cc1))
* add support for Postgres 15 ([#8215](https://github.com/parse-community/parse-server/issues/8215)) ([2feb6c4](https://github.com/parse-community/parse-server/commit/2feb6c46080946c984daa351187fa07cd582355d))
* liveQuery support for unsorted distance queries ([#8221](https://github.com/parse-community/parse-server/issues/8221)) ([0f763da](https://github.com/parse-community/parse-server/commit/0f763da17d646b2fec2cd980d3857e46072a8a07))
2022-11-19 03:37:26 +00:00
Manuel e373f09040 build: Release (#8324) 2022-11-19 04:30:10 +01:00
Manuel a9a9772b05 Merge branch 'release' into beta 2022-11-19 04:12:00 +01:00
semantic-release-bot c8d8e9fbad chore(release): 6.0.0-alpha.10 [skip ci]
# [6.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.9...6.0.0-alpha.10) (2022-11-19)

### Bug Fixes

* Cloud Code trigger `beforeSave` does not work with `Parse.Role` ([#8320](https://github.com/parse-community/parse-server/issues/8320)) ([f29d972](https://github.com/parse-community/parse-server/commit/f29d9720e9b37918fd885c97a31e34c42750e724))
2022-11-19 02:29:35 +00:00
dblythy f29d9720e9 fix: Cloud Code trigger beforeSave does not work with Parse.Role (#8320) 2022-11-19 03:27:51 +01:00
Manuel 4b1d46fb09 docs: fix PR template 2022-11-16 23:20:30 +01:00
Manuel 6e52ec7558 docs: change PR reference label in template 2022-11-16 23:18:40 +01:00
semantic-release-bot dd45eb2a11 chore(release): 6.0.0-alpha.9 [skip ci]
# [6.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.8...6.0.0-alpha.9) (2022-11-16)

### Features

* Remove deprecation `DEPPS3`: Config option `enforcePrivateUsers` defaults to `true` ([#8283](https://github.com/parse-community/parse-server/issues/8283)) ([ed499e3](https://github.com/parse-community/parse-server/commit/ed499e32a21bab9a874a9e5367dc71248ce836c4))

### BREAKING CHANGES

* The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283) ([ed499e3](ed499e3))
2022-11-16 22:01:42 +00:00
dblythy ed499e32a2 feat: Remove deprecation DEPPS3: Config option enforcePrivateUsers defaults to true (#8283)
BREAKING CHANGE: The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283)
2022-11-16 22:59:44 +01:00
semantic-release-bot 6e66b20e28 chore(release): 6.0.0-alpha.8 [skip ci]
# [6.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.7...6.0.0-alpha.8) (2022-11-11)

### Features

* Restrict use of `masterKey` to localhost by default ([#8281](https://github.com/parse-community/parse-server/issues/8281)) ([6c16021](https://github.com/parse-community/parse-server/commit/6c16021a1f03a70a6d9e68cb64df362d07f3b693))

### BREAKING CHANGES

* This release restricts the use of `masterKey` to localhost by default; if you are using Parse Dashboard on a different server to connect to Parse Server you need to add the IP address of the server that hosts Parse Dashboard to this option (#8281) ([6c16021](6c16021))
2022-11-11 02:27:01 +00:00
dblythy 6c16021a1f feat: Restrict use of masterKey to localhost by default (#8281)
BREAKING CHANGE: This release restricts the use of `masterKey` to localhost by default; if you are using Parse Dashboard on a different server to connect to Parse Server you need to add the IP address of the server that hosts Parse Dashboard to this option (#8281)
2022-11-11 03:24:48 +01:00
semantic-release-bot 7336afc562 chore(release): 6.0.0-alpha.7 [skip ci]
# [6.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.6...6.0.0-alpha.7) (2022-11-11)

### Features

* Upgrade Redis 3 to 4 ([#8293](https://github.com/parse-community/parse-server/issues/8293)) ([7d622f0](https://github.com/parse-community/parse-server/commit/7d622f06a4347e0ad2cba9a4ec07d8d4fb0f67bc))

### BREAKING CHANGES

* This release upgrades to Redis 4; if you are using the Redis cache adapter with Parse Server then this is a breaking change as the Redis client options have changed; see the [Redis migration guide](https://github.com/redis/node-redis/blob/redis%404.0.0/docs/v3-to-v4.md) for more details (#8293) ([7d622f0](7d622f0))
2022-11-11 00:18:30 +00:00
dblythy 7d622f06a4 feat: Upgrade Redis 3 to 4 (#8293)
BREAKING CHANGE: This release upgrades to Redis 4; if you are using the Redis cache adapter with Parse Server then this is a breaking change as the Redis client options have changed; see the [Redis migration guide](https://github.com/redis/node-redis/blob/redis%404.0.0/docs/v3-to-v4.md) for more details (#8293)
2022-11-11 01:16:50 +01:00
Manuel 9af9115f9d ci: Bump CI environments (#8312) 2022-11-11 00:13:36 +01:00
semantic-release-bot c8227cd140 chore(release): 6.0.0-alpha.6 [skip ci]
# [6.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.5...6.0.0-alpha.6) (2022-11-10)

### Features

* Remove support for MongoDB 4.0 ([#8292](https://github.com/parse-community/parse-server/issues/8292)) ([37245f6](https://github.com/parse-community/parse-server/commit/37245f62ce83516b6b95a54b850f0274ef680478))

### BREAKING CHANGES

* This release removes support for MongoDB 4.0; the new minimum supported MongoDB version is 4.2. which also removes support for the deprecated MongoDB MMAPv1 storage engine ([37245f6](37245f6))
2022-11-10 22:34:03 +00:00
dblythy 37245f62ce feat: Remove support for MongoDB 4.0 (#8292)
BREAKING CHANGE: This release removes support for MongoDB 4.0; the new minimum supported MongoDB version is 4.2. which also removes support for the deprecated MongoDB MMAPv1 storage engine
2022-11-10 22:21:11 +01:00
Manuel ccb14970cb docs: Update Node badge in README (#8311) 2022-11-10 22:05:16 +01:00
semantic-release-bot ebea057e5b chore(release): 6.0.0-alpha.5 [skip ci]
# [6.0.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.4...6.0.0-alpha.5) (2022-11-10)

### Bug Fixes

* Throwing error in Cloud Code Triggers `afterLogin`, `afterLogout` crashes server ([#8280](https://github.com/parse-community/parse-server/issues/8280)) ([130d290](https://github.com/parse-community/parse-server/commit/130d29074e3f763460e5685d0b9059e5a333caff))

### BREAKING CHANGES

* Throwing an error in Cloud Code Triggers `afterLogin`, `afterLogout` returns a rejected promise; in previous releases it crashed the server if you did not handle the error on the Node.js process level; consider adapting your code if your app currently handles these errors on the Node.js process level with `process.on('unhandledRejection', ...)` ([130d290](130d290))
2022-11-10 21:02:40 +00:00
dblythy 130d29074e fix: Throwing error in Cloud Code Triggers afterLogin, afterLogout crashes server (#8280)
BREAKING CHANGE: Throwing an error in Cloud Code Triggers `afterLogin`, `afterLogout` returns a rejected promise; in previous releases it crashed the server if you did not handle the error on the Node.js process level; consider adapting your code if your app currently handles these errors on the Node.js process level with `process.on('unhandledRejection', ...)`
2022-11-10 22:00:40 +01:00
semantic-release-bot 9d3c1c6918 chore(release): 6.0.0-alpha.4 [skip ci]
# [6.0.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.3...6.0.0-alpha.4) (2022-11-10)

### Features

* Remove deprecation `DEPPS2`: Config option `directAccess` defaults to true ([#8284](https://github.com/parse-community/parse-server/issues/8284)) ([f535ee6](https://github.com/parse-community/parse-server/commit/f535ee6ec2abba63f702127258ca49fa5b4e08c9))

### BREAKING CHANGES

* Config option `directAccess` defaults to true; set this to `false` in environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`. ([f535ee6](f535ee6))
2022-11-10 19:33:14 +00:00
dblythy f535ee6ec2 feat: Remove deprecation DEPPS2: Config option directAccess defaults to true (#8284)
BREAKING CHANGE: Config option `directAccess` defaults to true; set this to `false` in environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`.
2022-11-10 20:31:07 +01:00
semantic-release-bot 2054a88f19 chore(release): 6.0.0-alpha.3 [skip ci]
# [6.0.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.2...6.0.0-alpha.3) (2022-11-10)

### Features

* Remove deprecation `DEPPS4`: Remove convenience method for http request `Parse.Cloud.httpRequest`  ([#8287](https://github.com/parse-community/parse-server/issues/8287)) ([2d79c08](https://github.com/parse-community/parse-server/commit/2d79c0835b6a9acaf20d5c943d9b4619bb96831c))

### BREAKING CHANGES

* The convenience method for HTTP requests `Parse.Cloud.httpRequest` is removed; use your preferred 3rd party library for making HTTP requests ([2d79c08](2d79c08))
2022-11-10 17:30:57 +00:00
dblythy 2d79c0835b feat: Remove deprecation DEPPS4: Remove convenience method for http request Parse.Cloud.httpRequest (#8287)
BREAKING CHANGE: The convenience method for HTTP requests `Parse.Cloud.httpRequest` is removed; use your preferred 3rd party library for making HTTP requests
2022-11-10 18:28:49 +01:00
semantic-release-bot 739a3a9957 chore(release): 6.0.0-alpha.2 [skip ci]
# [6.0.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.1...6.0.0-alpha.2) (2022-11-10)

### Features

* Improve authentication adapter interface to support multi-factor authentication (MFA), authentication challenges, and provide a more powerful interface for writing custom authentication adapters ([#8156](https://github.com/parse-community/parse-server/issues/8156)) ([5bbf9ca](https://github.com/parse-community/parse-server/commit/5bbf9cade9a527787fd1002072d4013ab5d8db2b))
2022-11-10 16:37:32 +00:00
dblythy 5bbf9cade9 feat: Improve authentication adapter interface to support multi-factor authentication (MFA), authentication challenges, and provide a more powerful interface for writing custom authentication adapters (#8156) 2022-11-10 17:35:39 +01:00
semantic-release-bot 4eb5f28b04 chore(release): 6.0.0-alpha.1 [skip ci]
# [6.0.0-alpha.1](https://github.com/parse-community/parse-server/compare/5.4.0-alpha.1...6.0.0-alpha.1) (2022-11-10)

### Bug Fixes

* Remove Node 12 and Node 17 support ([#8279](https://github.com/parse-community/parse-server/issues/8279)) ([2546cc8](https://github.com/parse-community/parse-server/commit/2546cc8572bea6610cb9b3c7401d9afac0e3c1d6))

### BREAKING CHANGES

* This release removes Node 12 and Node 17 support ([2546cc8](2546cc8))
2022-11-10 15:37:25 +00:00
Manuel ed3248f9c6 ci: Bump node version in release workflow (#8310) 2022-11-10 16:35:41 +01:00
dblythy 2546cc8572 fix: Remove Node 12 and Node 17 support (#8279)
BREAKING CHANGE: This release removes Node 12 and Node 17 support
2022-11-10 16:15:55 +01:00
Manuel 7cb266b207 refactor: Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) (#8308) 2022-11-10 00:24:42 +01:00
Manuel 735669a86a refactor: Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) (#8307) 2022-11-10 00:24:26 +01:00
semantic-release-bot fd8a11bc27 chore(release): 5.3.3 [skip ci]
## [5.3.3](https://github.com/parse-community/parse-server/compare/5.3.2...5.3.3) (2022-11-09)

### Bug Fixes

* Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) ([#8305](https://github.com/parse-community/parse-server/issues/8305)) ([60c5a73](https://github.com/parse-community/parse-server/commit/60c5a73d257e0d536056b38bdafef8b7130524d8))
2022-11-09 20:56:00 +00:00
Manuel 60c5a73d25 fix: Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) (#8305) 2022-11-09 21:32:02 +01:00
semantic-release-bot 3e983c41ff chore(release): 5.3.2 [skip ci]
## [5.3.2](https://github.com/parse-community/parse-server/compare/5.3.1...5.3.2) (2022-11-09)

### Bug Fixes

* Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) ([#8302](https://github.com/parse-community/parse-server/issues/8302)) ([6728da1](https://github.com/parse-community/parse-server/commit/6728da1e3591db1e27031d335d64d8f25546a06f))
2022-11-09 19:12:19 +00:00
Manuel d27dfa3464 refactor: Parse Server option requestKeywordDenylist can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) (#8304) 2022-11-09 20:02:05 +01:00
Manuel d9c3c02e7d refactor: Parse Server option requestKeywordDenylist can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) (#8303) 2022-11-09 20:01:39 +01:00
Manuel 6728da1e35 fix: Parse Server option requestKeywordDenylist can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) (#8302) 2022-11-09 20:00:29 +01:00
Manuel 43194b1bbe docs: add branch CI badges to README 2022-11-09 17:19:39 +01:00
Parse Platform a8cb2a4ef1 refactor: Upgrade pg-promise from 10.12.0 to 10.12.1 (#8299) 2022-11-08 15:35:46 +00:00
Manuel 46dbecdec1 refactor: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) (#8298) 2022-11-07 23:49:41 +01:00
Manuel 42581225f1 refactor: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) (#8297) 2022-11-07 23:17:03 +01:00
semantic-release-bot 2458a8c58d chore(release): 5.3.1 [skip ci]
## [5.3.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.3.1) (2022-11-07)

### Bug Fixes

* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) ([#8295](https://github.com/parse-community/parse-server/issues/8295)) ([50eed3c](https://github.com/parse-community/parse-server/commit/50eed3cffe80fadfb4bdac52b2783a18da2cfc4f))
2022-11-07 22:10:47 +00:00
Manuel 50eed3cffe fix: Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) (#8295) 2022-11-07 23:03:24 +01:00
Snyk bot 81304be649 refactor: Upgrade jwks-rsa from 2.1.4 to 2.1.5 (#8278) 2022-11-03 02:29:13 +01:00
Antoine Cormouls e90a5183ec refactor: replace deprecated LRU cache methods (#8266) 2022-11-01 21:33:14 +01:00
semantic-release-bot 963613ec3f chore(release): 5.4.0-alpha.1 [skip ci]
# [5.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.4.0-alpha.1) (2022-10-31)

### Bug Fixes

* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] ([#8187](https://github.com/parse-community/parse-server/issues/8187)) ([8c8ec71](https://github.com/parse-community/parse-server/commit/8c8ec715739e0f851338cfed794409ebac66c51b))
* brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) ([#8146](https://github.com/parse-community/parse-server/issues/8146)) [skip release] ([4c0c7c7](https://github.com/parse-community/parse-server/commit/4c0c7c77b76257878b9bcb05ff9de01c9d790262))
* certificate in Apple Game Center auth adapter not validated [skip release] ([#8058](https://github.com/parse-community/parse-server/issues/8058)) ([75af9a2](https://github.com/parse-community/parse-server/commit/75af9a26cc8e9e88a33d1e452c93a0ee6e509f17))
* graphQL query ignores condition `equalTo` with value `false` ([#8032](https://github.com/parse-community/parse-server/issues/8032)) ([7f5a15d](https://github.com/parse-community/parse-server/commit/7f5a15d5df0dfa3515e9f73709d6a49663545f9b))
* internal indices for classes `_Idempotency` and `_Role` are not protected in defined schema ([#8121](https://github.com/parse-community/parse-server/issues/8121)) ([c16f529](https://github.com/parse-community/parse-server/commit/c16f529f74f92154401bf662f634b3c5fa45e18e))
* invalid file request not properly handled [skip release] ([#8062](https://github.com/parse-community/parse-server/issues/8062)) ([4c9e956](https://github.com/parse-community/parse-server/commit/4c9e95674ad081f13062e8cd30b77b1962d5df57))
* liveQuery with `containedIn` not working when object field is an array ([#8128](https://github.com/parse-community/parse-server/issues/8128)) ([1d9605b](https://github.com/parse-community/parse-server/commit/1d9605bc93009263d3811df4d4249034ba6eb8c4))
* protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] ([#8076](https://github.com/parse-community/parse-server/issues/8076)) ([9fd4516](https://github.com/parse-community/parse-server/commit/9fd4516cde5c742f9f29dd05468b4a43a85639a6))
* push notifications `badge` doesn't update with Installation beforeSave trigger ([#8162](https://github.com/parse-community/parse-server/issues/8162)) ([3c75c2b](https://github.com/parse-community/parse-server/commit/3c75c2ba4851fae96a8c19b11a3efde03816c9a1))
* query aggregation pipeline cannot handle value of type `Date` when `directAccess: true` ([#8167](https://github.com/parse-community/parse-server/issues/8167)) ([e424137](https://github.com/parse-community/parse-server/commit/e4241374061caef66538de15112fb6bbafb1f5bb))
* relation constraints in compound queries `Parse.Query.or`, `Parse.Query.and` not working ([#8203](https://github.com/parse-community/parse-server/issues/8203)) ([28f0d26](https://github.com/parse-community/parse-server/commit/28f0d2667787d2ac68726607b811d6f0ef62b9f1))
* security upgrade undici from 5.6.0 to 5.8.0 ([#8108](https://github.com/parse-community/parse-server/issues/8108)) ([4aa016b](https://github.com/parse-community/parse-server/commit/4aa016b7322467422b9fdf05d8e29b9ecf910da7))
* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] ([#8238](https://github.com/parse-community/parse-server/issues/8238)) ([c03908f](https://github.com/parse-community/parse-server/commit/c03908f74e5c9eed834874a89df6c89c1a1e849f))
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] ([#8180](https://github.com/parse-community/parse-server/issues/8180)) ([37fed30](https://github.com/parse-community/parse-server/commit/37fed3062ccc3ef1dfd49a9fc53318e72b3e4aff))
* sorting by non-existing value throws `INVALID_SERVER_ERROR` on Postgres ([#8157](https://github.com/parse-community/parse-server/issues/8157)) ([3b775a1](https://github.com/parse-community/parse-server/commit/3b775a1fb8a1878714e3451191438963d688f1b0))
* updating object includes unchanged keys in client response for certain key types ([#8159](https://github.com/parse-community/parse-server/issues/8159)) ([37af1d7](https://github.com/parse-community/parse-server/commit/37af1d78fce5a15039ffe3af7b323c1f1e8582fc))

### Features

* add convenience access to Parse Server configuration in Cloud Code via `Parse.Server` ([#8244](https://github.com/parse-community/parse-server/issues/8244)) ([9f11115](https://github.com/parse-community/parse-server/commit/9f111158edf7fd57a65db0c4f9244b37e58cf293))
* add option to change the default value of the `Parse.Query.limit()` constraint ([#8152](https://github.com/parse-community/parse-server/issues/8152)) ([0388956](https://github.com/parse-community/parse-server/commit/038895680894984e569dff54bf5c7b31094f3891))
* add support for MongoDB 6 ([#8242](https://github.com/parse-community/parse-server/issues/8242)) ([aba0081](https://github.com/parse-community/parse-server/commit/aba0081ce1a166a93de57f3928c19a05562b5cc1))
* add support for Postgres 15 ([#8215](https://github.com/parse-community/parse-server/issues/8215)) ([2feb6c4](https://github.com/parse-community/parse-server/commit/2feb6c46080946c984daa351187fa07cd582355d))
* liveQuery support for unsorted distance queries ([#8221](https://github.com/parse-community/parse-server/issues/8221)) ([0f763da](https://github.com/parse-community/parse-server/commit/0f763da17d646b2fec2cd980d3857e46072a8a07))
2022-10-31 14:37:28 +00:00
Snyk bot 70ada3e522 refactor: upgrade express from 4.18.1 to 4.18.2 (#8265) 2022-10-31 15:29:32 +01:00
semantic-release-bot 0e30c76e39 chore(release): 5.4.0-beta.1 [skip ci]
# [5.4.0-beta.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.4.0-beta.1) (2022-10-29)

### Bug Fixes

* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] ([#8187](https://github.com/parse-community/parse-server/issues/8187)) ([8c8ec71](https://github.com/parse-community/parse-server/commit/8c8ec715739e0f851338cfed794409ebac66c51b))
* brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) ([#8146](https://github.com/parse-community/parse-server/issues/8146)) [skip release] ([4c0c7c7](https://github.com/parse-community/parse-server/commit/4c0c7c77b76257878b9bcb05ff9de01c9d790262))
* certificate in Apple Game Center auth adapter not validated [skip release] ([#8058](https://github.com/parse-community/parse-server/issues/8058)) ([75af9a2](https://github.com/parse-community/parse-server/commit/75af9a26cc8e9e88a33d1e452c93a0ee6e509f17))
* graphQL query ignores condition `equalTo` with value `false` ([#8032](https://github.com/parse-community/parse-server/issues/8032)) ([7f5a15d](https://github.com/parse-community/parse-server/commit/7f5a15d5df0dfa3515e9f73709d6a49663545f9b))
* internal indices for classes `_Idempotency` and `_Role` are not protected in defined schema ([#8121](https://github.com/parse-community/parse-server/issues/8121)) ([c16f529](https://github.com/parse-community/parse-server/commit/c16f529f74f92154401bf662f634b3c5fa45e18e))
* invalid file request not properly handled [skip release] ([#8062](https://github.com/parse-community/parse-server/issues/8062)) ([4c9e956](https://github.com/parse-community/parse-server/commit/4c9e95674ad081f13062e8cd30b77b1962d5df57))
* liveQuery with `containedIn` not working when object field is an array ([#8128](https://github.com/parse-community/parse-server/issues/8128)) ([1d9605b](https://github.com/parse-community/parse-server/commit/1d9605bc93009263d3811df4d4249034ba6eb8c4))
* protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] ([#8076](https://github.com/parse-community/parse-server/issues/8076)) ([9fd4516](https://github.com/parse-community/parse-server/commit/9fd4516cde5c742f9f29dd05468b4a43a85639a6))
* push notifications `badge` doesn't update with Installation beforeSave trigger ([#8162](https://github.com/parse-community/parse-server/issues/8162)) ([3c75c2b](https://github.com/parse-community/parse-server/commit/3c75c2ba4851fae96a8c19b11a3efde03816c9a1))
* query aggregation pipeline cannot handle value of type `Date` when `directAccess: true` ([#8167](https://github.com/parse-community/parse-server/issues/8167)) ([e424137](https://github.com/parse-community/parse-server/commit/e4241374061caef66538de15112fb6bbafb1f5bb))
* relation constraints in compound queries `Parse.Query.or`, `Parse.Query.and` not working ([#8203](https://github.com/parse-community/parse-server/issues/8203)) ([28f0d26](https://github.com/parse-community/parse-server/commit/28f0d2667787d2ac68726607b811d6f0ef62b9f1))
* security upgrade undici from 5.6.0 to 5.8.0 ([#8108](https://github.com/parse-community/parse-server/issues/8108)) ([4aa016b](https://github.com/parse-community/parse-server/commit/4aa016b7322467422b9fdf05d8e29b9ecf910da7))
* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] ([#8238](https://github.com/parse-community/parse-server/issues/8238)) ([c03908f](https://github.com/parse-community/parse-server/commit/c03908f74e5c9eed834874a89df6c89c1a1e849f))
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] ([#8180](https://github.com/parse-community/parse-server/issues/8180)) ([37fed30](https://github.com/parse-community/parse-server/commit/37fed3062ccc3ef1dfd49a9fc53318e72b3e4aff))
* sorting by non-existing value throws `INVALID_SERVER_ERROR` on Postgres ([#8157](https://github.com/parse-community/parse-server/issues/8157)) ([3b775a1](https://github.com/parse-community/parse-server/commit/3b775a1fb8a1878714e3451191438963d688f1b0))
* updating object includes unchanged keys in client response for certain key types ([#8159](https://github.com/parse-community/parse-server/issues/8159)) ([37af1d7](https://github.com/parse-community/parse-server/commit/37af1d78fce5a15039ffe3af7b323c1f1e8582fc))

### Features

* add convenience access to Parse Server configuration in Cloud Code via `Parse.Server` ([#8244](https://github.com/parse-community/parse-server/issues/8244)) ([9f11115](https://github.com/parse-community/parse-server/commit/9f111158edf7fd57a65db0c4f9244b37e58cf293))
* add option to change the default value of the `Parse.Query.limit()` constraint ([#8152](https://github.com/parse-community/parse-server/issues/8152)) ([0388956](https://github.com/parse-community/parse-server/commit/038895680894984e569dff54bf5c7b31094f3891))
* add support for MongoDB 6 ([#8242](https://github.com/parse-community/parse-server/issues/8242)) ([aba0081](https://github.com/parse-community/parse-server/commit/aba0081ce1a166a93de57f3928c19a05562b5cc1))
* add support for Postgres 15 ([#8215](https://github.com/parse-community/parse-server/issues/8215)) ([2feb6c4](https://github.com/parse-community/parse-server/commit/2feb6c46080946c984daa351187fa07cd582355d))
* liveQuery support for unsorted distance queries ([#8221](https://github.com/parse-community/parse-server/issues/8221)) ([0f763da](https://github.com/parse-community/parse-server/commit/0f763da17d646b2fec2cd980d3857e46072a8a07))
2022-10-29 20:01:12 +00:00
Manuel 1d277db467 build: beta release (#8264) 2022-10-29 21:53:56 +02:00
Manuel 5e9d494979 Merge branch 'beta' into build-beta 2022-10-29 21:31:22 +02:00
semantic-release-bot 12e174bcb6 chore(release): 5.3.0 [skip ci]
# [5.3.0](https://github.com/parse-community/parse-server/compare/5.2.8...5.3.0) (2022-10-29)

### Bug Fixes

* afterSave trigger removes pointer in Parse object ([#7913](https://github.com/parse-community/parse-server/issues/7913)) ([47d796e](https://github.com/parse-community/parse-server/commit/47d796ea58f65e71612ce37149be692abc9ea97f))
* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] ([#8188](https://github.com/parse-community/parse-server/issues/8188)) ([1a2b1b9](https://github.com/parse-community/parse-server/commit/1a2b1b9bc18012acc019ec2b5ee16fddfa41de41))
* auto-release process may fail if optional back-merging task fails ([#8051](https://github.com/parse-community/parse-server/issues/8051)) ([cf925e7](https://github.com/parse-community/parse-server/commit/cf925e75e87a6989f41e2e2abb2aba4332b1e79f))
* brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) ([#8145](https://github.com/parse-community/parse-server/issues/8145)) [skip release] ([f0db4ca](https://github.com/parse-community/parse-server/commit/f0db4ca4a45208e6c86e21ce563105977c2b1c1f))
* certificate in Apple Game Center auth adapter not validated [skip release] ([#8055](https://github.com/parse-community/parse-server/issues/8055)) ([4c2aa63](https://github.com/parse-community/parse-server/commit/4c2aa63fd2f4ee6cca48b051b7d345ca7c975591))
* custom database options are not passed to MongoDB GridFS ([#7911](https://github.com/parse-community/parse-server/issues/7911)) ([b1e5565](https://github.com/parse-community/parse-server/commit/b1e5565b22f2eff229571fe9a9500314bd30965b))
* depreciate allowClientClassCreation defaulting to true ([#7925](https://github.com/parse-community/parse-server/issues/7925)) ([38ed96a](https://github.com/parse-community/parse-server/commit/38ed96ace534d639db007aa7dd5387b2da8f03ae))
* errors in GraphQL do not show the original error but a general `Unexpected Error` ([#8045](https://github.com/parse-community/parse-server/issues/8045)) ([0d81887](https://github.com/parse-community/parse-server/commit/0d818879c217f9c56100a5f59868fa37e6d24b71))
* interrupted WebSocket connection not closed by LiveQuery server ([#8012](https://github.com/parse-community/parse-server/issues/8012)) ([2d5221e](https://github.com/parse-community/parse-server/commit/2d5221e48012fb7781c0406d543a922d313075ea))
* invalid file request not properly handled [skip release] ([#8061](https://github.com/parse-community/parse-server/issues/8061)) ([1a04a34](https://github.com/parse-community/parse-server/commit/1a04a347cf5e015069fd133bfc7d2566374c99d7))
* live query role cache does not clear when a user is added to a role ([#8026](https://github.com/parse-community/parse-server/issues/8026)) ([199dfc1](https://github.com/parse-community/parse-server/commit/199dfc17226d85a78ab85f24362cce740f4ada39))
* peer dependency mismatch for GraphQL dependencies ([#7934](https://github.com/parse-community/parse-server/issues/7934)) ([0a6faa8](https://github.com/parse-community/parse-server/commit/0a6faa81fa97f8620e7fd05e8c7bbdb4b7da9578))
* protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] ([#8075](https://github.com/parse-community/parse-server/issues/8075)) ([636d16e](https://github.com/parse-community/parse-server/commit/636d16e0f9f40bbb68ae2b32bcb4d016c1cd749c))
* return correct response when revert is used in beforeSave ([#7839](https://github.com/parse-community/parse-server/issues/7839)) ([19900fc](https://github.com/parse-community/parse-server/commit/19900fcdf8c9f29a674fb62cf6e4b3341d796891))
* security upgrade @parse/fs-files-adapter from 1.2.1 to 1.2.2 ([#7948](https://github.com/parse-community/parse-server/issues/7948)) ([3a70fda](https://github.com/parse-community/parse-server/commit/3a70fda6798d4143f21046439b5eaf232a31bdb6))
* security upgrade moment from 2.29.1 to 2.29.2 ([#7931](https://github.com/parse-community/parse-server/issues/7931)) ([731c550](https://github.com/parse-community/parse-server/commit/731c5507144bbacff236097e7a2a03bfe54f6e10))
* security upgrade parse push adapter from 4.1.0 to 4.1.2 ([#7893](https://github.com/parse-community/parse-server/issues/7893)) ([93667b4](https://github.com/parse-community/parse-server/commit/93667b4e8402bf13b46c4d3ef12cec6532fd9da7))
* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] ([#8237](https://github.com/parse-community/parse-server/issues/8237)) ([4c1befa](https://github.com/parse-community/parse-server/commit/4c1befabf2e40bf3cf41b8b3db257435684f7a62))
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] ([#8181](https://github.com/parse-community/parse-server/issues/8181)) ([83cdc89](https://github.com/parse-community/parse-server/commit/83cdc89be994416f74533030b90e8d1dd82fec57))
* websocket connection of LiveQuery interrupts frequently ([#8048](https://github.com/parse-community/parse-server/issues/8048)) ([03caae1](https://github.com/parse-community/parse-server/commit/03caae1e611f28079cdddbbe433daaf69e3f595c))

### Features

* add MongoDB 5.1 compatibility ([#7682](https://github.com/parse-community/parse-server/issues/7682)) ([022a856](https://github.com/parse-community/parse-server/commit/022a85619d8a2c57a2f2938e245e4d8a47c15276))
* add MongoDB 5.2 support ([#7894](https://github.com/parse-community/parse-server/issues/7894)) ([5bfa716](https://github.com/parse-community/parse-server/commit/5bfa7160d9e35b237cbae1016ed86724aa99f8d7))
* add support for Node 17 and 18 ([#7896](https://github.com/parse-community/parse-server/issues/7896)) ([3e9f292](https://github.com/parse-community/parse-server/commit/3e9f292d840334244934cee9a34545ac86313549))
* align file trigger syntax with class trigger; use the new syntax `Parse.Cloud.beforeSave(Parse.File, (request) => {})`, the old syntax `Parse.Cloud.beforeSaveFile((request) => {})` has been deprecated ([#7966](https://github.com/parse-community/parse-server/issues/7966)) ([c6dcad8](https://github.com/parse-community/parse-server/commit/c6dcad8d167d44912dbd416d328519314c0809bd))
* replace GraphQL Apollo with GraphQL Yoga ([#7967](https://github.com/parse-community/parse-server/issues/7967)) ([1aa2204](https://github.com/parse-community/parse-server/commit/1aa2204aebfdbe273d54d6d56c6029f7c34aab14))
* selectively enable / disable default authentication adapters ([#7953](https://github.com/parse-community/parse-server/issues/7953)) ([c1e808f](https://github.com/parse-community/parse-server/commit/c1e808f9e807fc49508acbde0d8b3f2b901a1638))
* upgrade mongodb from 4.4.1 to 4.5.0 ([#7991](https://github.com/parse-community/parse-server/issues/7991)) ([e692b5d](https://github.com/parse-community/parse-server/commit/e692b5dd8214cdb0ce79bedd30d9aa3cf4de76a5))

### Performance Improvements

* reduce database operations when using the constant parameter in Cloud Function validation ([#7892](https://github.com/parse-community/parse-server/issues/7892)) ([041197f](https://github.com/parse-community/parse-server/commit/041197fb4ca1cd7cf18dc426ce38647267823668))
2022-10-29 19:11:33 +00:00
Manuel 254954064f build: release (#8263) 2022-10-29 21:04:12 +02:00
Manuel 50409aa866 Merge branch 'release' into build-release 2022-10-29 19:58:37 +02:00
semantic-release-bot 9053e79151 chore(release): 5.3.0-alpha.32 [skip ci]
# [5.3.0-alpha.32](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.31...5.3.0-alpha.32) (2022-10-29)

### Features

* add convenience access to Parse Server configuration in Cloud Code via `Parse.Server` ([#8244](https://github.com/parse-community/parse-server/issues/8244)) ([9f11115](https://github.com/parse-community/parse-server/commit/9f111158edf7fd57a65db0c4f9244b37e58cf293))
2022-10-29 17:10:47 +00:00
dblythy 9f111158ed feat: add convenience access to Parse Server configuration in Cloud Code via Parse.Server (#8244) 2022-10-29 19:03:31 +02:00
Snyk bot eab9cdd749 refactor: upgrade body-parser from 1.20.0 to 1.20.1 (#8262) 2022-10-29 17:39:56 +02:00
Parse Platform 4918665dd2 refactor: upgrade semver from 7.3.7 to 7.3.8 (#8261) 2022-10-27 14:04:09 +02:00
dblythy c41e5fca95 ci: remove running CI for superseded commits (#8213) 2022-10-27 10:36:52 +02:00
semantic-release-bot b54af6b701 chore(release): 5.3.0-alpha.31 [skip ci]
# [5.3.0-alpha.31](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.30...5.3.0-alpha.31) (2022-10-24)

### Bug Fixes

* relation constraints in compound queries `Parse.Query.or`, `Parse.Query.and` not working ([#8203](https://github.com/parse-community/parse-server/issues/8203)) ([28f0d26](https://github.com/parse-community/parse-server/commit/28f0d2667787d2ac68726607b811d6f0ef62b9f1))
2022-10-24 10:54:30 +00:00
dblythy 28f0d26677 fix: relation constraints in compound queries Parse.Query.or, Parse.Query.and not working (#8203) 2022-10-24 12:45:17 +02:00
dependabot[bot] fb503320c3 refactor: bump async from 3.2.1 to 3.2.4 (#8254) 2022-10-20 22:43:34 +02:00
Parse Platform a0499521cc refactor: upgrade pg-monitor from 1.4.1 to 1.5.0 (#8248) 2022-10-20 22:03:20 +02:00
Parse Platform b2491234e8 refactor: upgrade ws from 8.8.1 to 8.9.0 (#8247) 2022-10-19 10:04:34 +02:00
Manuel 8863ad2309 docs: remove differentiation between MongoDB 5.x versions (#8246) 2022-10-17 23:04:45 +02:00
semantic-release-bot 3cde50f82a chore(release): 5.3.0-alpha.30 [skip ci]
# [5.3.0-alpha.30](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.29...5.3.0-alpha.30) (2022-10-17)

### Features

* add support for MongoDB 6 ([#8242](https://github.com/parse-community/parse-server/issues/8242)) ([aba0081](https://github.com/parse-community/parse-server/commit/aba0081ce1a166a93de57f3928c19a05562b5cc1))
2022-10-17 17:29:15 +00:00
Manuel aba0081ce1 feat: add support for MongoDB 6 (#8242) 2022-10-17 19:21:32 +02:00
dblythy 4af13af991 ci: reduce timeout after idempotency tests (#8227) 2022-10-17 01:53:10 +02:00
Manuel 2b00c5b762 docs: change backmerge instructions in contribution docs 2022-10-16 00:53:24 +02:00
semantic-release-bot c1a70fe820 chore(release): 5.3.0-alpha.29 [skip ci]
# [5.3.0-alpha.29](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.28...5.3.0-alpha.29) (2022-10-15)

### Bug Fixes

* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] ([#8238](https://github.com/parse-community/parse-server/issues/8238)) ([c03908f](https://github.com/parse-community/parse-server/commit/c03908f74e5c9eed834874a89df6c89c1a1e849f))

### Features

* add support for Postgres 15 ([#8215](https://github.com/parse-community/parse-server/issues/8215)) ([2feb6c4](https://github.com/parse-community/parse-server/commit/2feb6c46080946c984daa351187fa07cd582355d))
2022-10-15 22:26:12 +00:00
Corey 2feb6c4608 feat: add support for Postgres 15 (#8215) 2022-10-16 00:16:29 +02:00
Snyk bot 6d0bc1eff0 refactor: upgrade follow-redirects from 1.15.1 to 1.15.2 (#8233) 2022-10-15 17:12:27 +02:00
Manuel c03908f74e fix: server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] (#8238) 2022-10-15 01:06:45 +02:00
semantic-release-bot 8011b2fdac chore(release): 5.2.8 [skip ci]
## [5.2.8](https://github.com/parse-community/parse-server/compare/5.2.7...5.2.8) (2022-10-14)

### Bug Fixes

* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) ([#8235](https://github.com/parse-community/parse-server/issues/8235)) ([066f296](https://github.com/parse-community/parse-server/commit/066f29673ab4030b6b5b90c0c0326f7d3fe7612a))
2022-10-14 22:55:38 +00:00
Manuel 4c1befabf2 fix: server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] (#8237) 2022-10-15 00:54:08 +02:00
Manuel 066f29673a fix: server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) (#8235) 2022-10-15 00:48:22 +02:00
Snyk bot 89fad24bae refactor: upgrade mongodb from 4.9.1 to 4.10.0 (#8234) 2022-10-14 19:17:30 +02:00
semantic-release-bot 8c30c81da6 chore(release): 5.3.0-alpha.28 [skip ci]
# [5.3.0-alpha.28](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.27...5.3.0-alpha.28) (2022-10-11)

### Features

* liveQuery support for unsorted distance queries ([#8221](https://github.com/parse-community/parse-server/issues/8221)) ([0f763da](https://github.com/parse-community/parse-server/commit/0f763da17d646b2fec2cd980d3857e46072a8a07))
2022-10-11 22:36:58 +00:00
Diamond Lewis 0f763da17d feat: liveQuery support for unsorted distance queries (#8221) 2022-10-12 00:27:29 +02:00
dblythy 2a82d19dbd refactor: code style fixes with prettier and lint (#8208) 2022-10-03 13:55:05 +02:00
Parse Platform 63d51fa6c8 refactor: upgrade @graphql-tools/merge from 8.3.5 to 8.3.6 (#8206) 2022-10-01 21:41:10 +02:00
Parse Platform a0956b5496 refactor: upgrade @graphql-tools/schema from 9.0.3 to 9.0.4 (#8207) 2022-10-01 16:13:21 +02:00
Parse Platform 777b4a9961 refactor: upgrade @graphql-tools/utils from 8.11.0 to 8.12.0 (#8205) 2022-10-01 14:26:53 +02:00
Manuel 566592e443 docs: add FAQs to contribution guide 2022-10-01 13:58:47 +02:00
Manuel 65330e022f docs: update contribution guide 2022-10-01 13:47:27 +02:00
dblythy eb649f226f test: fix flaky Apple Game Center tests (#8204) 2022-10-01 12:14:59 +02:00
semantic-release-bot 5376c3b145 chore(release): 5.3.0-alpha.27 [skip ci]
# [5.3.0-alpha.27](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.26...5.3.0-alpha.27) (2022-09-29)

### Bug Fixes

* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] ([#8187](https://github.com/parse-community/parse-server/issues/8187)) ([8c8ec71](https://github.com/parse-community/parse-server/commit/8c8ec715739e0f851338cfed794409ebac66c51b))
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] ([#8180](https://github.com/parse-community/parse-server/issues/8180)) ([37fed30](https://github.com/parse-community/parse-server/commit/37fed3062ccc3ef1dfd49a9fc53318e72b3e4aff))

### Features

* add option to change the default value of the `Parse.Query.limit()` constraint ([#8152](https://github.com/parse-community/parse-server/issues/8152)) ([0388956](https://github.com/parse-community/parse-server/commit/038895680894984e569dff54bf5c7b31094f3891))
2022-09-29 23:02:45 +00:00
vzukanov 0388956808 feat: add option to change the default value of the Parse.Query.limit() constraint (#8152) 2022-09-30 00:38:57 +02:00
Manuel b96a4cbdc5 docs: minor rephrasing in contribution docs 2022-09-29 12:34:29 +02:00
Manuel 5908a40d2f docs: minor rephrasing in CONTRIBUTING docs 2022-09-28 15:44:20 +02:00
Manuel b2dd1d9c0f docs: add contribution FAQs (#8201) 2022-09-28 15:22:21 +02:00
Parse Platform c9bd87e2f3 refactor: upgrade @graphql-tools/merge from 8.3.4 to 8.3.5 (#8199) 2022-09-28 02:04:47 +02:00
Parse Platform c1dbd007c5 refactor: upgrade @graphql-tools/utils from 8.10.1 to 8.11.0 (#8198) 2022-09-28 00:06:25 +02:00
Parse Platform 9872051e3b refactor: upgrade @graphql-tools/schema from 9.0.2 to 9.0.3 (#8197) 2022-09-27 22:27:25 +02:00
Parse Platform 643d49199a refactor: upgrade uuid from 8.3.2 to 9.0.0 (#8200) 2022-09-27 13:01:54 +02:00
Manuel ae8d08294b ci: adapt to new MongoDB lifecycle schedule (#8195) 2022-09-26 15:08:12 +02:00
Corey 377ce67239 ci: upgrade Postgres versions (#8191) 2022-09-24 01:06:22 +02:00
Manuel eb20e92f8f docs: update Parse Server support for Postgres table 2022-09-22 22:44:36 +02:00
Snyk bot e8242423e4 refactor: upgrade mongodb from 4.9.0 to 4.9.1 (#8190) 2022-09-22 11:27:47 +02:00
Manuel d9afeb86a5 docs: remove diamond sponsors from README 2022-09-20 23:22:19 +02:00
Manuel 8c8ec71573 fix: authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration appIds is set as a string (e.g. abc) instead of an array of strings (e.g. ["abc"]) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] (#8187) 2022-09-20 23:05:44 +02:00
Manuel 1a2b1b9bc1 fix: authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration appIds is set as a string (e.g. abc) instead of an array of strings (e.g. ["abc"]) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] (#8188) 2022-09-20 23:03:21 +02:00
semantic-release-bot e6dc487963 chore(release): 5.2.7 [skip ci]
## [5.2.7](https://github.com/parse-community/parse-server/compare/5.2.6...5.2.7) (2022-09-20)

### Bug Fixes

* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) ([#8185](https://github.com/parse-community/parse-server/issues/8185)) ([ecf0814](https://github.com/parse-community/parse-server/commit/ecf0814499bde31ab6082b6e42854aa65ad2e03e))
2022-09-20 20:43:51 +00:00
Manuel ecf0814499 fix: authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration appIds is set as a string (e.g. abc) instead of an array of strings (e.g. ["abc"]) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) (#8185) 2022-09-20 22:31:19 +02:00
Manuel 83cdc89be9 fix: session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] (#8181) 2022-09-20 02:36:54 +02:00
semantic-release-bot 7aac70cca6 chore(release): 5.2.6 [skip ci]
## [5.2.6](https://github.com/parse-community/parse-server/compare/5.2.5...5.2.6) (2022-09-20)

### Bug Fixes

* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) ([#8182](https://github.com/parse-community/parse-server/issues/8182)) ([6d0b2f5](https://github.com/parse-community/parse-server/commit/6d0b2f534603301bb630d9c8e497af3bc7ff1d09))
2022-09-20 00:27:18 +00:00
Manuel 37fed3062c fix: session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] (#8180) 2022-09-20 02:23:49 +02:00
Manuel 6d0b2f5346 fix: session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) (#8182) 2022-09-20 02:18:07 +02:00
Snyk bot 004faf41e4 refactor: upgrade @graphql-tools/merge from 8.3.3 to 8.3.4 (#8175) 2022-09-19 22:07:14 +02:00
Snyk bot bf7d5ba605 refactor: upgrade @graphql-tools/schema from 9.0.1 to 9.0.2 (#8176) 2022-09-19 20:07:26 +02:00
Snyk bot 6fb4d68f4c refactor: upgrade pg-promise from 10.11.1 to 10.12.0 (#8178) 2022-09-19 16:35:20 +02:00
Snyk bot 9fe16738b6 refactor: upgrade @graphql-tools/utils from 8.10.0 to 8.10.1 (#8177) 2022-09-19 15:45:00 +02:00
dblythy df12ba3ba2 docs: regenerate API docs (#8179) 2022-09-19 12:40:15 +02:00
dblythy a5ba5da36d docs: describe additional database options (#8173) 2022-09-18 18:44:31 +02:00
semantic-release-bot b2fe087a02 chore(release): 5.3.0-alpha.26 [skip ci]
# [5.3.0-alpha.26](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.25...5.3.0-alpha.26) (2022-09-17)

### Bug Fixes

* sorting by non-existing value throws `INVALID_SERVER_ERROR` on Postgres ([#8157](https://github.com/parse-community/parse-server/issues/8157)) ([3b775a1](https://github.com/parse-community/parse-server/commit/3b775a1fb8a1878714e3451191438963d688f1b0))
2022-09-17 18:49:17 +00:00
dblythy 3b775a1fb8 fix: sorting by non-existing value throws INVALID_SERVER_ERROR on Postgres (#8157) 2022-09-17 20:41:45 +02:00
semantic-release-bot 73e1763a63 chore(release): 5.3.0-alpha.25 [skip ci]
# [5.3.0-alpha.25](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.24...5.3.0-alpha.25) (2022-09-17)

### Bug Fixes

* updating object includes unchanged keys in client response for certain key types ([#8159](https://github.com/parse-community/parse-server/issues/8159)) ([37af1d7](https://github.com/parse-community/parse-server/commit/37af1d78fce5a15039ffe3af7b323c1f1e8582fc))
2022-09-17 16:30:24 +00:00
dblythy 37af1d78fc fix: updating object includes unchanged keys in client response for certain key types (#8159) 2022-09-17 18:20:50 +02:00
semantic-release-bot 41e44302b4 chore(release): 5.3.0-alpha.24 [skip ci]
# [5.3.0-alpha.24](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.23...5.3.0-alpha.24) (2022-09-17)

### Bug Fixes

* query aggregation pipeline cannot handle value of type `Date` when `directAccess: true` ([#8167](https://github.com/parse-community/parse-server/issues/8167)) ([e424137](https://github.com/parse-community/parse-server/commit/e4241374061caef66538de15112fb6bbafb1f5bb))
2022-09-17 14:26:53 +00:00
dblythy e424137406 fix: query aggregation pipeline cannot handle value of type Date when directAccess: true (#8167) 2022-09-17 16:19:28 +02:00
semantic-release-bot cec3071170 chore(release): 5.3.0-alpha.23 [skip ci]
# [5.3.0-alpha.23](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.22...5.3.0-alpha.23) (2022-09-17)

### Bug Fixes

* liveQuery with `containedIn` not working when object field is an array ([#8128](https://github.com/parse-community/parse-server/issues/8128)) ([1d9605b](https://github.com/parse-community/parse-server/commit/1d9605bc93009263d3811df4d4249034ba6eb8c4))
2022-09-17 12:10:06 +00:00
Stew 1d9605bc93 fix: liveQuery with containedIn not working when object field is an array (#8128) 2022-09-17 13:59:45 +02:00
semantic-release-bot 4a45cc467c chore(release): 5.3.0-alpha.22 [skip ci]
# [5.3.0-alpha.22](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.21...5.3.0-alpha.22) (2022-09-16)

### Bug Fixes

* brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) ([#8146](https://github.com/parse-community/parse-server/issues/8146)) [skip release] ([4c0c7c7](https://github.com/parse-community/parse-server/commit/4c0c7c77b76257878b9bcb05ff9de01c9d790262))
* push notifications `badge` doesn't update with Installation beforeSave trigger ([#8162](https://github.com/parse-community/parse-server/issues/8162)) ([3c75c2b](https://github.com/parse-community/parse-server/commit/3c75c2ba4851fae96a8c19b11a3efde03816c9a1))
2022-09-16 19:50:56 +00:00
dblythy 3c75c2ba48 fix: push notifications badge doesn't update with Installation beforeSave trigger (#8162) 2022-09-16 21:43:03 +02:00
dependabot[bot] 5250c07a1c refactor: bump jose from 2.0.5 to 2.0.6 (#8171) 2022-09-16 21:03:05 +02:00
Manuel 1109d0ca23 docs: fix link of official parse email adapter 2022-09-16 11:35:41 +02:00
Manuel 9cd4a35120 ci: add code scanning (#8169) 2022-09-14 23:38:37 +02:00
dblythy c85bc016e2 ci: fix flaky Apple Game Center tests (#8163) 2022-09-14 16:33:55 +02:00
Parse Platform 7c32bfe95f refactor: upgrade mongodb from 4.8.1 to 4.9.0 (#8158) 2022-09-10 10:55:03 +02:00
Snyk bot 07acecdc77 refactor: upgrade winston from 3.8.0 to 3.8.1 (#8155) 2022-09-09 01:20:44 +02:00
Parse Platform dfe9168512 refactor: upgrade graphql from 16.5.0 to 16.6.0 (#8154) 2022-09-08 17:32:39 +02:00
dependabot[bot] 780ee0203a refactor: bump node-fetch from 3.2.4 to 3.2.10 (#8150) 2022-09-04 17:32:27 +02:00
Snyk bot 6a2651c325 refactor: upgrade @graphql-tools/schema from 9.0.0 to 9.0.1 (#8147) 2022-09-04 14:01:16 +02:00
Snyk bot a2d0de7656 refactor: upgrade mongodb from 4.7.0 to 4.8.1 (#8148) 2022-09-04 11:46:36 +02:00
Snyk bot 149884fe3e refactor: upgrade mongodb from 4.6.0 to 4.7.0 (#8083) 2022-09-03 11:22:42 +02:00
Snyk bot f821dfd02a refactor: upgrade @graphql-tools/utils from 8.9.1 to 8.10.0 (#8142) 2022-09-03 02:20:43 +02:00
Manuel 4c0c7c77b7 fix: brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) (#8146) [skip release] 2022-09-02 21:43:31 +02:00
Manuel f0db4ca4a4 fix: brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) (#8145) [skip release] 2022-09-02 21:43:09 +02:00
semantic-release-bot 83fd16c1b9 chore(release): 5.2.5 [skip ci]
## [5.2.5](https://github.com/parse-community/parse-server/compare/5.2.4...5.2.5) (2022-09-02)

### Bug Fixes

* brute force guessing of user sensitive data via search patterns; this fixes a security vulnerability in which internal and protected fields may be used as query constraints to guess the value of these fields and obtain sensitive data (GHSA-2m6g-crv8-p3c6) ([#8144](https://github.com/parse-community/parse-server/issues/8144)) ([e39d51b](https://github.com/parse-community/parse-server/commit/e39d51bd329cd978589983bd659db46e1d45aad4))
2022-09-02 19:20:39 +00:00
Manuel e39d51bd32 fix: brute force guessing of user sensitive data via search patterns; this fixes a security vulnerability in which internal and protected fields may be used as query constraints to guess the value of these fields and obtain sensitive data (GHSA-2m6g-crv8-p3c6) (#8144) 2022-09-02 21:13:18 +02:00
Snyk bot 5432082d82 refactor: upgrade @graphql-tools/merge from 8.3.2 to 8.3.3 (#8141) 2022-09-02 18:49:04 +02:00
Snyk bot 3de466ba9b refactor: upgrade @graphql-tools/schema from 8.5.1 to 9.0.0 (#8138) 2022-09-02 17:37:40 +02:00
Snyk bot 82eb4613d9 refactor: upgrade @graphql-tools/utils from 8.9.0 to 8.9.1 (#8140) 2022-08-31 19:19:10 +02:00
Snyk bot 276c32a0dd refactor: upgrade @graphql-tools/merge from 8.3.1 to 8.3.2 (#8139) 2022-08-31 13:24:47 +02:00
Snyk bot 4de1c9bdd5 refactor: upgrade @graphql-tools/schema from 8.5.0 to 8.5.1 (#8130) 2022-08-25 14:03:01 +02:00
Snyk bot 0287098ef5 refactor: upgrade @graphql-tools/merge from 8.3.0 to 8.3.1 (#8131) 2022-08-22 19:55:17 +02:00
Snyk bot ef5d59d784 refactor: upgrade @graphql-tools/utils from 8.6.13 to 8.9.0 (#8129) 2022-08-19 12:42:11 +02:00
dependabot[bot] 1db432db51 refactor: bump semver-regex and husky (#8134) 2022-08-19 00:31:14 +02:00
dependabot[bot] 54649eca67 refactor: upgrade @actions/core from 1.2.6 to 1.9.1 (#8132) 2022-08-18 23:57:20 +02:00
dependabot[bot] f693b55b1c refactor: upgrade undici from 5.8.0 to 5.9.1 (#8133) 2022-08-18 22:25:22 +02:00
Manuel 5c2d2c5193 refactor: upgrade ws from 8.8.0 to 8.8.1 (#8123) 2022-08-06 16:15:13 +02:00
semantic-release-bot eef750aa3e chore(release): 5.3.0-alpha.21 [skip ci]
# [5.3.0-alpha.21](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.20...5.3.0-alpha.21) (2022-08-05)

### Bug Fixes

* internal indices for classes `_Idempotency` and `_Role` are not protected in defined schema ([#8121](https://github.com/parse-community/parse-server/issues/8121)) ([c16f529](https://github.com/parse-community/parse-server/commit/c16f529f74f92154401bf662f634b3c5fa45e18e))
2022-08-05 09:34:45 +00:00
Antoine Cormouls c16f529f74 fix: internal indices for classes _Idempotency and _Role are not protected in defined schema (#8121) 2022-08-05 11:25:02 +02:00
Snyk bot 3351ca7cec refactor: upgrade lru-cache from 7.10.2 to 7.12.0 (#8114) 2022-07-27 01:37:32 +02:00
Antonio Davi Macedo Coelho de Castro 2ea4e37a37 refactor: upgrade ldapjs from 2.3.2 to 2.3.3 (#8091) 2022-07-25 23:59:31 +02:00
Snyk bot 1246551be3 refactor: upgrade lru-cache from 7.10.1 to 7.10.2 (#8102) 2022-07-25 14:09:27 +02:00
semantic-release-bot 145008c7d1 chore(release): 5.3.0-alpha.20 [skip ci]
# [5.3.0-alpha.20](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.19...5.3.0-alpha.20) (2022-07-22)

### Bug Fixes

* security upgrade undici from 5.6.0 to 5.8.0 ([#8108](https://github.com/parse-community/parse-server/issues/8108)) ([4aa016b](https://github.com/parse-community/parse-server/commit/4aa016b7322467422b9fdf05d8e29b9ecf910da7))
2022-07-22 18:18:50 +00:00
dependabot[bot] 4aa016b732 fix: security upgrade undici from 5.6.0 to 5.8.0 (#8108) 2022-07-22 20:11:21 +02:00
Snyk bot a96e15b3f7 refactor: upgrade @graphql-tools/merge from 8.2.15 to 8.3.0 (#8106) 2022-07-21 00:27:35 +02:00
Snyk bot 861fb211c7 refactor: upgrade @graphql-tools/schema from 8.3.14 to 8.5.0 (#8104) 2022-07-19 18:34:00 +02:00
Snyk bot 266011c5a5 refactor: upgrade winston from 3.7.2 to 3.8.0 (#8103) 2022-07-17 13:37:15 +02:00
dependabot[bot] e93a0aab57 refactor: bump moment from 2.29.3 to 2.29.4 (#8101) 2022-07-15 22:39:48 +02:00
Snyk bot 24fe6dc939 refactor: upgrade @graphql-tools/merge from 8.2.14 to 8.2.15 (#8100) 2022-07-15 12:55:10 +02:00
dependabot[bot] 38ba9b4f47 refactor: bump undici from 5.2.0 to 5.6.0 (#8094) 2022-07-03 13:45:01 +02:00
semantic-release-bot e3f634e740 chore(release): 5.3.0-alpha.19 [skip ci]
# [5.3.0-alpha.19](https://github.com/parse-community/parse-server/compare/5.3.0-alpha.18...5.3.0-alpha.19) (2022-07-03)

### Bug Fixes

* certificate in Apple Game Center auth adapter not validated [skip release] ([#8058](https://github.com/parse-community/parse-server/issues/8058)) ([75af9a2](https://github.com/parse-community/parse-server/commit/75af9a26cc8e9e88a33d1e452c93a0ee6e509f17))
* graphQL query ignores condition `equalTo` with value `false` ([#8032](https://github.com/parse-community/parse-server/issues/8032)) ([7f5a15d](https://github.com/parse-community/parse-server/commit/7f5a15d5df0dfa3515e9f73709d6a49663545f9b))
* invalid file request not properly handled [skip release] ([#8062](https://github.com/parse-community/parse-server/issues/8062)) ([4c9e956](https://github.com/parse-community/parse-server/commit/4c9e95674ad081f13062e8cd30b77b1962d5df57))
* protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] ([#8076](https://github.com/parse-community/parse-server/issues/8076)) ([9fd4516](https://github.com/parse-community/parse-server/commit/9fd4516cde5c742f9f29dd05468b4a43a85639a6))
2022-07-03 10:30:00 +00:00
Jong Eun Lee 7f5a15d5df fix: graphQL query ignores condition equalTo with value false (#8032) 2022-07-03 12:13:10 +02:00
Diamond Lewis 6e68656629 refactor: upgrade @graphql-tools/merge from 8.2.13 to 8.2.14 (#8085) 2022-07-03 11:33:30 +02:00
Antonio Davi Macedo Coelho de Castro 0d16a64eea refactor: upgrade ws from 8.7.0 to 8.8.0 (#8092) 2022-07-02 11:36:03 +02:00
Diamond Lewis abd8536f48 refactor: upgrade @graphql-tools/utils from 8.6.12 to 8.6.13 (#8086) 2022-06-30 23:50:12 +02:00
Diamond Lewis 65ce27440a refactor: upgrade @graphql-tools/schema from 8.3.13 to 8.3.14 (#8087) 2022-06-30 16:41:34 +02:00
Manuel 9fd4516cde fix: protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] (#8076) 2022-06-30 13:01:40 +02:00
Manuel 636d16e0f9 fix: protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] (#8075) 2022-06-30 12:53:31 +02:00
semantic-release-bot e42be5c526 chore(release): 5.2.4 [skip ci]
## [5.2.4](https://github.com/parse-community/parse-server/compare/5.2.3...5.2.4) (2022-06-30)

### Bug Fixes

* protected fields exposed via LiveQuery; this removes protected fields from the client response; this may be a breaking change if your app is currently expecting to receive these protected fields ([GHSA-crrq-vr9j-fxxh](https://github.com/parse-community/parse-server/security/advisories/GHSA-crrq-vr9j-fxxh)) (https://github.com/parse-community/parse-server/pull/8074) ([#8073](https://github.com/parse-community/parse-server/issues/8073)) ([309f64c](https://github.com/parse-community/parse-server/commit/309f64ced8700321df056fb3cc97f15007a00df1))
2022-06-30 10:46:12 +00:00
Manuel 309f64ced8 fix: protected fields exposed via LiveQuery; this removes protected fields from the client response; this may be a breaking change if your app is currently expecting to receive these protected fields ([GHSA-crrq-vr9j-fxxh](https://github.com/parse-community/parse-server/security/advisories/GHSA-crrq-vr9j-fxxh)) (https://github.com/parse-community/parse-server/pull/8074) (#8073) 2022-06-30 12:26:39 +02:00
Diamond Lewis e8eb546c90 refactor: upgrade jwks-rsa from 2.1.3 to 2.1.4 (#8088) 2022-06-30 11:28:33 +02:00
Manuel 0fd600cf24 docs: add template and issue link requirements (#8080) 2022-06-28 11:18:02 +02:00
Manuel 35cd6910de docs: add LTS explanation and open vulnerabilities to README (#8077) 2022-06-28 10:19:48 +02:00
Manuel 7844442840 docs: add missing heading to commit message section (#8079) 2022-06-28 10:03:40 +02:00
Antonio Davi Macedo Coelho de Castro 42c9543189 refactor: upgrade winston-daily-rotate-file from 4.6.1 to 4.7.1 (#8066) 2022-06-22 22:14:03 +02:00
Snyk bot 86832b9b95 refactor: upgrade follow-redirects from 1.15.0 to 1.15.1 (#8063) 2022-06-19 15:48:12 +02:00
Snyk bot e26beb1f5c refactor: upgrade ws from 8.6.0 to 8.7.0 (#8064) 2022-06-19 10:12:20 +02:00
Manuel 4c9e95674a fix: invalid file request not properly handled [skip release] (#8062) 2022-06-18 02:38:04 +02:00
Manuel 1a04a347cf fix: invalid file request not properly handled [skip release] (#8061) 2022-06-18 02:15:08 +02:00
semantic-release-bot eb2952fff7 chore(release): 5.2.3 [skip ci]
## [5.2.3](https://github.com/parse-community/parse-server/compare/5.2.2...5.2.3) (2022-06-17)

### Bug Fixes

* invalid file request not properly handled; this fixes a security vulnerability in which an invalid file request can crash the server ([GHSA-xw6g-jjvf-wwf9](https://github.com/parse-community/parse-server/security/advisories/GHSA-xw6g-jjvf-wwf9)) ([#8060](https://github.com/parse-community/parse-server/issues/8060)) ([5be375d](https://github.com/parse-community/parse-server/commit/5be375dec2fa35425c1003ae81c55995ac72af92))
2022-06-17 23:40:39 +00:00
Manuel 5be375dec2 fix: invalid file request not properly handled; this fixes a security vulnerability in which an invalid file request can crash the server ([GHSA-xw6g-jjvf-wwf9](https://github.com/parse-community/parse-server/security/advisories/GHSA-xw6g-jjvf-wwf9)) (#8060) 2022-06-18 01:33:19 +02:00
Manuel 75af9a26cc fix: certificate in Apple Game Center auth adapter not validated [skip release] (#8058) 2022-06-17 20:22:35 +02:00
Manuel 4c2aa63fd2 fix: certificate in Apple Game Center auth adapter not validated [skip release] (#8055) 2022-06-17 19:32:30 +02:00
Manuel 4a1039679c docs: add release instructions (#8056) 2022-06-17 19:31:49 +02:00
semantic-release-bot ed0baa87af chore(release): 5.2.2 [skip ci]
## [5.2.2](https://github.com/parse-community/parse-server/compare/5.2.1...5.2.2) (2022-06-17)

### Bug Fixes

* certificate in Apple Game Center auth adapter not validated; this fixes a security vulnerability in which authentication could be bypassed using a fake certificate; if you are using the Apple Gamer Center auth adapter it is your responsibility to keep its root certificate up-to-date and we advice you read the security advisory ([GHSA-rh9j-f5f8-rvgc](https://github.com/parse-community/parse-server/security/advisories/GHSA-rh9j-f5f8-rvgc)) ([ba2b0a9](https://github.com/parse-community/parse-server/commit/ba2b0a9cb9a568817a114b132a4c2e0911d76df1))
2022-06-17 16:36:47 +00:00
Manuel ba2b0a9cb9 fix: certificate in Apple Game Center auth adapter not validated; this fixes a security vulnerability in which authentication could be bypassed using a fake certificate; if you are using the Apple Gamer Center auth adapter it is your responsibility to keep its root certificate up-to-date and we advice you read the security advisory ([GHSA-rh9j-f5f8-rvgc](https://github.com/parse-community/parse-server/security/advisories/GHSA-rh9j-f5f8-rvgc)) 2022-06-17 18:29:26 +02:00
206 changed files with 45477 additions and 13604 deletions
+3 -2
View File
@@ -6,8 +6,9 @@
"presets": [
["@babel/preset-env", {
"targets": {
"node": "12"
}
"node": "14",
},
"exclude": ["proposal-dynamic-import"]
}]
],
"sourceMaps": "inline"
-2
View File
@@ -1,8 +1,6 @@
node_modules
npm-debug.log
*.md
PATENTS
LICENSE
Dockerfile
.dockerignore
.gitignore
+8 -3
View File
@@ -5,13 +5,14 @@
"node": true,
"es6": true
},
"parser": "babel-eslint",
"parser": "@babel/eslint-parser",
"plugins": [
"flowtype"
],
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
"sourceType": "module",
"requireConfigFile": false
},
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
@@ -23,6 +24,10 @@
"prefer-const": "error",
"space-infix-ops": "error",
"no-useless-escape": "off",
"require-atomic-updates": "off"
"require-atomic-updates": "off",
"object-curly-spacing": ["error", "always"]
},
"globals": {
"Parse": true
}
}
+1
View File
@@ -8,3 +8,4 @@
[options]
suppress_comment= \\(.\\|\n\\)*\\@flow-disable-next
esproposal.optional_chaining=enable
@@ -8,16 +8,10 @@ assignees: ''
---
### New Issue Checklist
<!--
Check every following box [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Platform!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/master/SUPPORT.md).
- [ ] I have searched through [existing issues](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
- [ ] I can reproduce the issue with the [latest version of Parse Server](https://github.com/parse-community/parse-server/releases). <!-- We don't investigate issues for outdated releases. -->
- Report security issues [confidentially](https://github.com/parse-community/parse-server/security/policy).
- Any contribution is under this [license](https://github.com/parse-community/parse-server/blob/alpha/LICENSE).
- Before posting search [existing issues](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
### Issue Description
<!-- What is the specific issue with Parse Server? -->
@@ -30,6 +24,7 @@ assignees: ''
### Expected Outcome
<!-- What outcome, for example query result, did you expect? -->
### Environment
<!-- Be specific with versions, don't use "latest" or semver ranges like "~x.y.z" or "^x.y.z". -->
@@ -8,15 +8,10 @@ assignees: ''
---
### New Feature / Enhancement Checklist
<!--
Check every following box [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Platform!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/master/SUPPORT.md).
- [ ] I have searched through [existing issues](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
- Report security issues [confidentially](https://github.com/parse-community/parse-server/security/policy).
- Any contribution is under this [license](https://github.com/parse-community/parse-server/blob/alpha/LICENSE).
- Before posting search [existing issues](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
### Current Limitation
<!-- Which current limitation is the feature or enhancement addressing? -->
+14
View File
@@ -0,0 +1,14 @@
# Dependabot dependency updates
# Docs: https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm"
# Location of package-lock.json
directory: "/"
# Check daily for updates
schedule:
interval: "daily"
commit-message:
# Set commit message prefix
prefix: "refactor"
+12 -20
View File
@@ -1,29 +1,21 @@
### New Pull Request Checklist
<!--
Please check the following boxes [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Server!
-->
## Pull Request
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [ ] I am creating this PR in reference to an [issue](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
- Report security issues [confidentially](https://github.com/parse-community/parse-server/security/policy).
- Any contribution is under this [license](https://github.com/parse-community/parse-server/blob/alpha/LICENSE).
- Link this pull request to an [issue](https://github.com/parse-community/parse-server/issues?q=is%3Aissue).
### Issue Description
<!-- Add a brief description of the issue this PR solves. -->
## Issue
<!-- Add the link to the issue that this PR closes. -->
Related issue: FILL_THIS_OUT
Closes: FILL_THIS_OUT
### Approach
<!-- Add a description of the approach in this PR. -->
## Approach
<!-- Describe the changes in this PR. -->
### TODOs before merging
<!--
Add TODOs that need to be completed before merging this PR.
Delete suggested TODOs that do not apply to this PR.
-->
## Tasks
<!-- Delete tasks that don't apply. -->
- [ ] Add tests
- [ ] Add changes to documentation (guides, repository pages, in-code descriptions)
- [ ] Add changes to documentation (guides, repository pages, code comments)
- [ ] Add [security check](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#security-checks)
- [ ] Add new Parse Error codes to Parse JS SDK <!-- no hard-coded error codes in Parse Server -->
- [x] A changelog entry is created automatically using the pull request title (do not manually add a changelog entry)
@@ -13,18 +13,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout default branch
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: 14
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: CI Environments Check
@@ -36,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout default branch
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Compose branch name for PR
id: branch
run: echo "::set-output name=name::ci-bump-environment"
+164 -140
View File
@@ -1,26 +1,65 @@
name: ci
on:
push:
branches: [ release, alpha, beta, next-major ]
branches: [release, alpha, beta, next-major, 'release-[0-9]+.x.x']
pull_request:
branches:
- '**'
paths-ignore:
- '**/**.md'
env:
NODE_VERSION: 16.14.2
NODE_VERSION: 20.12.0
PARSE_SERVER_TEST_TIMEOUT: 20000
jobs:
check-code-analysis:
name: Code Analysis
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ['javascript']
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
source-root: src
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
check-ci:
name: Node Engine Check
timeout-minutes: 15
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install prod dependencies
run: npm ci
- name: Remove dev dependencies
run: ./ci/uninstallDevDeps.sh @actions/core
- name: CI Node Engine Check
run: npm run ci:checkNodeEngine
check-lint:
name: Lint
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
@@ -28,150 +67,118 @@ jobs:
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- name: CI Node Engine Check
run: npm run ci:checkNodeEngine
check-lint:
name: Lint
timeout-minutes: 15
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: npm run lint
- run: npm run lint
check-definitions:
name: Check Definitions
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- name: CI Definitions Check
run: npm run ci:definitionsCheck
check-circular:
name: Circular Dependencies
timeout-minutes: 5
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: npm run madge:circular
name: Circular Dependencies
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: npm run madge:circular
check-docker:
name: Docker Build
timeout-minutes: 15
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Build docker image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64
platforms: linux/amd64, linux/arm64/v8
check-lock-file-version:
name: NPM Lock File Version
timeout-minutes: 5
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Check NPM lock file version
uses: mansona/npm-lockfile-version@v1
with:
version: 1
version: 2
check-mongo:
strategy:
matrix:
include:
- name: MongoDB 5.2, ReplicaSet, WiredTiger
MONGODB_VERSION: 5.2.1
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 14.19.1
- name: MongoDB 5.1, ReplicaSet, WiredTiger
MONGODB_VERSION: 5.1.1
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 14.19.1
- name: MongoDB 5.0, ReplicaSet, WiredTiger
MONGODB_VERSION: 5.0.6
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.14.2
- name: MongoDB 4.4, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.4.13
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.14.2
- name: MongoDB 4.2, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.2.19
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.14.2
- name: MongoDB 4.0, ReplicaSet, WiredTiger
MONGODB_VERSION: 4.0.28
MONGODB_TOPOLOGY: replicaset
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.14.2
- name: MongoDB 4.0, Standalone, MMAPv1
MONGODB_VERSION: 4.0.28
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: mmapv1
NODE_VERSION: 16.14.2
- name: MongoDB 4.2, ReplicaSet
MONGODB_VERSION: 4.2.25
MONGODB_TOPOLOGY: replset
NODE_VERSION: 20.12.0
- name: MongoDB 4.4, ReplicaSet
MONGODB_VERSION: 4.4.29
MONGODB_TOPOLOGY: replset
NODE_VERSION: 20.12.0
- name: MongoDB 5, ReplicaSet
MONGODB_VERSION: 5.0.26
MONGODB_TOPOLOGY: replset
NODE_VERSION: 20.12.0
- name: MongoDB 6, ReplicaSet
MONGODB_VERSION: 6.0.14
MONGODB_TOPOLOGY: replset
NODE_VERSION: 20.12.0
- name: MongoDB 7, ReplicaSet
MONGODB_VERSION: 7.0.8
MONGODB_TOPOLOGY: replset
NODE_VERSION: 20.12.0
- name: Redis Cache
PARSE_SERVER_TEST_CACHE: redis
MONGODB_VERSION: 4.4.13
MONGODB_VERSION: 7.0.8
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 16.14.2
- name: Node 12
MONGODB_VERSION: 4.4.13
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 12.22.11
- name: Node 14
MONGODB_VERSION: 4.4.13
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 14.19.1
- name: Node 17
MONGODB_VERSION: 4.4.13
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 17.9.0
NODE_VERSION: 20.12.0
- name: Node 18
MONGODB_VERSION: 4.4.13
MONGODB_VERSION: 7.0.8
MONGODB_TOPOLOGY: standalone
MONGODB_STORAGE_ENGINE: wiredTiger
NODE_VERSION: 18.1.0
NODE_VERSION: 18.20.0
fail-fast: false
name: ${{ matrix.name }}
timeout-minutes: 15
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
services:
redis:
image: redis
ports:
- 6379:6379
env:
- 6379:6379
env:
MONGODB_VERSION: ${{ matrix.MONGODB_VERSION }}
MONGODB_TOPOLOGY: ${{ matrix.MONGODB_TOPOLOGY }}
MONGODB_STORAGE_ENGINE: ${{ matrix.MONGODB_STORAGE_ENGINE }}
@@ -180,13 +187,13 @@ jobs:
steps:
- name: Fix usage of insecure GitHub protocol
run: sudo git config --system url."https://github".insteadOf "git://github"
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.NODE_VERSION }}
- name: Cache Node.js modules
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
@@ -198,33 +205,41 @@ jobs:
- run: npm run coverage
env:
CI: true
- run: bash <(curl -s https://codecov.io/bash)
- name: Upload code coverage
uses: codecov/codecov-action@v4
with:
# Set to `true` once codecov token bug is fixed; https://github.com/parse-community/parse-server/issues/9129
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
check-postgres:
strategy:
matrix:
include:
- name: PostgreSQL 11, PostGIS 3.0
POSTGRES_IMAGE: postgis/postgis:11-3.0
NODE_VERSION: 16.14.2
- name: PostgreSQL 11, PostGIS 3.1
POSTGRES_IMAGE: postgis/postgis:11-3.1
NODE_VERSION: 16.14.2
- name: PostgreSQL 11, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:11-3.2
NODE_VERSION: 16.14.2
- name: PostgreSQL 12, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:12-3.2
NODE_VERSION: 16.14.2
- name: PostgreSQL 13, PostGIS 3.1
POSTGRES_IMAGE: postgis/postgis:13-3.1
NODE_VERSION: 20.12.0
- name: PostgreSQL 13, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:13-3.2
NODE_VERSION: 16.14.2
- name: PostgreSQL 14, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:14-3.2
NODE_VERSION: 16.14.2
NODE_VERSION: 20.12.0
- name: PostgreSQL 13, PostGIS 3.3
POSTGRES_IMAGE: postgis/postgis:13-3.3
NODE_VERSION: 20.12.0
- name: PostgreSQL 13, PostGIS 3.4
POSTGRES_IMAGE: postgis/postgis:13-3.4
NODE_VERSION: 20.12.0
- name: PostgreSQL 14, PostGIS 3.4
POSTGRES_IMAGE: postgis/postgis:14-3.4
NODE_VERSION: 20.12.0
- name: PostgreSQL 15, PostGIS 3.4
POSTGRES_IMAGE: postgis/postgis:15-3.4
NODE_VERSION: 20.12.0
- name: PostgreSQL 16, PostGIS 3.4
POSTGRES_IMAGE: postgis/postgis:15-3.4
NODE_VERSION: 20.12.0
fail-fast: false
name: ${{ matrix.name }}
timeout-minutes: 15
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
services:
redis:
image: redis
@@ -246,13 +261,13 @@ jobs:
PARSE_SERVER_TEST_DATABASE_URI: postgres://postgres:postgres@localhost:5432/parse_server_postgres_adapter_test_database
NODE_VERSION: ${{ matrix.NODE_VERSION }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.NODE_VERSION }}
- name: Cache Node.js modules
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
@@ -266,4 +281,13 @@ jobs:
- run: npm run coverage
env:
CI: true
- run: bash <(curl -s https://codecov.io/bash)
- name: Upload code coverage
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -1,74 +0,0 @@
# This scheduler creates pull requests to prepare for releases in intervals according to the
# release cycle of this repository.
name: release-automated-scheduler
on:
# Scheduler temporarily disabled until stable release of Parse Server 5 with all branches (alpha, beta, release) created
# schedule:
# - cron: 0 0 1 * *
workflow_dispatch:
jobs:
create-pr-release:
runs-on: ubuntu-latest
steps:
- name: Checkout beta branch
uses: actions/checkout@v2
with:
ref: beta
- name: Compose branch name for PR
id: branch
run: echo "::set-output name=name::build-release-${{ github.run_id }}${{ github.run_number }}"
- name: Create branch
run: |
git config --global user.email ${{ github.actor }}@users.noreply.github.com
git config --global user.name ${{ github.actor }}
git checkout -b ${{ steps.branch.outputs.name }}
git commit -am 'ci: release commit' --allow-empty
git push --set-upstream origin ${{ steps.branch.outputs.name }}
- name: Create PR
uses: k3rnels-actions/pr-update@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
pr_title: "build: release"
pr_source: ${{ steps.branch.outputs.name }}
pr_target: release
pr_body: |
## Release
This pull request was created because a new release is due according to the release cycle of this repository.
Just resolve any conflicts and it's good to merge. Any version increment will be done by release automation.
*⚠️ Use `Merge commit` to merge this pull request. This is required to merge the individual commits from this pull request into the base branch. Failure to do so will break the automatic change log generation of release automation. Do not use "Squash and merge"!*
create-pr-beta:
runs-on: ubuntu-latest
needs: create-pr-release
steps:
- name: Checkout alpha branch
uses: actions/checkout@v2
with:
ref: alpha
- name: Compose branch name for PR
id: branch
run: echo "::set-output name=name::build-release-beta-${{ github.run_id }}${{ github.run_number }}"
- name: Create branch
run: |
git config --global user.email ${{ github.actor }}@users.noreply.github.com
git config --global user.name ${{ github.actor }}
git checkout -b ${{ steps.branch.outputs.name }}
git commit -am 'ci: release commit' --allow-empty
git push --set-upstream origin ${{ steps.branch.outputs.name }}
- name: Create PR
uses: k3rnels-actions/pr-update@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
pr_title: "build: release beta"
pr_source: ${{ steps.branch.outputs.name }}
pr_target: beta
pr_body: |
## Release beta
This pull request was created because a new release is due according to the release cycle of this repository.
Just resolve any conflicts and it's good to merge. Any version increment will be done by release automation.
*⚠️ Use `Merge commit` to merge this pull request. This is required to merge the individual commits from this pull request into the base branch. Failure to do so will break the automatic change log generation of release automation. Do not use "Squash and merge"!*
+19 -19
View File
@@ -1,7 +1,7 @@
name: release-automated
on:
push:
branches: [ release, alpha, beta, next-major ]
branches: [ release, alpha, beta, next-major, 'release-[0-9]+.x.x' ]
jobs:
release:
runs-on: ubuntu-latest
@@ -12,15 +12,15 @@ jobs:
- name: Determine trigger branch name
id: branch
run: echo "::set-output name=trigger_branch::${GITHUB_REF#refs/*/}"
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v2
- uses: actions/setup-node@v4
with:
node-version: 14
node-version: 20
registry-url: https://registry.npmjs.org/
- name: Cache Node.js modules
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -42,7 +42,7 @@ jobs:
env:
REGISTRY: docker.io
IMAGE_NAME: parseplatform/parse-server
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
@@ -51,23 +51,23 @@ jobs:
id: branch
run: echo "::set-output name=branch_name::${GITHUB_REF#refs/*/}"
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: ${{ needs.release.outputs.current_tag }}
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Log into Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
@@ -75,10 +75,10 @@ jobs:
tags: |
type=semver,pattern={{version}},value=${{ needs.release.outputs.current_tag }}
- name: Build and push Docker image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64/v8
platforms: linux/amd64, linux/arm64/v8
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
@@ -86,16 +86,16 @@ jobs:
docs:
needs: release
if: needs.release.outputs.current_tag != '' && github.ref == 'refs/heads/release'
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: 14
node-version: 18.20.0
- name: Cache Node.js modules
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -112,4 +112,4 @@ jobs:
uses: peaceiris/actions-gh-pages@v3.7.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
publish_dir: ./docs
+8 -8
View File
@@ -14,7 +14,7 @@ env:
IMAGE_NAME: parseplatform/parse-server
jobs:
build:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
@@ -23,23 +23,23 @@ jobs:
id: branch
run: echo "::set-output name=branch_name::${GITHUB_REF#refs/*/}"
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref }}
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Log into Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
@@ -48,10 +48,10 @@ jobs:
type=semver,enable=true,pattern={{version}},value=${{ github.event.inputs.ref }}
type=raw,enable=${{ github.event.inputs.ref == '' }},value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64/v8
platforms: linux/amd64, linux/arm64/v8
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+18 -14
View File
@@ -2,8 +2,13 @@
* Semantic Release Config
*/
const fs = require('fs').promises;
const path = require('path');
const { readFile } = require('fs').promises;
const { resolve } = require('path');
// For ES6 modules use:
// import { readFile } from 'fs/promises';
// import { resolve, dirname } from 'path';
// import { fileURLToPath } from 'url';
// Get env vars
const ref = process.env.GITHUB_REF;
@@ -24,7 +29,7 @@ const templates = {
async function config() {
// Get branch
const branch = ref.split('/').pop();
const branch = ref?.split('/')?.pop()?.split('-')[0] || '(current branch could not be determined)';
console.log(`Running on branch: ${branch}`);
// Set changelog file
@@ -40,11 +45,8 @@ async function config() {
{ name: 'alpha', prerelease: true },
{ name: 'beta', prerelease: true },
'next-major',
// Long-Term-Support branches
// { name: 'release-1', range: '1.x.x', channel: '1.x' },
// { name: 'release-2', range: '2.x.x', channel: '2.x' },
// { name: 'release-3', range: '3.x.x', channel: '3.x' },
// { name: 'release-4', range: '4.x.x', channel: '4.x' },
// Long-Term-Support branch of previous major version
'release-6.x.x',
],
dryRun: false,
debug: true,
@@ -92,7 +94,7 @@ async function config() {
[
"@saithodev/semantic-release-backmerge",
{
"branches": [
"backmergeBranches": [
{ from: "beta", to: "alpha" },
{ from: "release", to: "beta" },
]
@@ -106,15 +108,17 @@ async function config() {
async function loadTemplates() {
for (const template of Object.keys(templates)) {
const text = await readFile(path.resolve(__dirname, resourcePath, templates[template].file));
// For ES6 modules use:
// const fileUrl = import.meta.url;
// const __dirname = dirname(fileURLToPath(fileUrl));
const filePath = resolve(__dirname, resourcePath, templates[template].file);
const text = await readFile(filePath, 'utf-8');
templates[template].text = text;
}
}
async function readFile(filePath) {
return await fs.readFile(filePath, 'utf-8');
}
function getReleaseComment() {
const url = repositoryUrl + '/releases/tag/${nextRelease.gitTag}';
const comment = '🎉 This change has been released in version [${nextRelease.version}](' + url + ')';
-82
View File
@@ -1,82 +0,0 @@
# Upgrading Parse Server to version 2.3.0
Parse Server version 2.3.0 begins using unique indexes to ensure the User's username and email are unique. This is not a backwards incompatible change, but it may in some cases cause a significant performance regression until the index finishes building. Building the unique index before upgrading your Parse Server version will eliminate the performance impact, and is a recommended step before upgrading any app to Parse Server 2.3.0. New apps starting with version 2.3.0 do not need to take any steps before beginning their project.
If you are using MongoDB in Cluster or Replica Set mode, we recommend reading Mongo's [documentation on index building](https://docs.mongodb.com/v3.0/tutorial/build-indexes-on-replica-sets/) first. If you are not using these features, you can execute the following commands from the Mongo shell to build the unique index. You may also want to create a backup first.
```js
// Select the database that your Parse App uses
use parse;
// Select the collection your Parse App uses for users. For migrated apps, this probably includes a collectionPrefix.
var coll = db['your_prefix:_User'];
// You can check if the indexes already exists by running coll.getIndexes()
coll.getIndexes();
// The indexes you want should look like this. If they already exist, you can skip creating them.
{
"v" : 1,
"unique" : true,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "parse.your_prefix:_User",
"background" : true,
"sparse" : true
}
{
"v" : 1,
"unique" : true,
"key" : {
"email" : 1
},
"name" : "email_1",
"ns" : "parse.your_prefix:_User",
"background" : true,
"sparse" : true
}
// Create the username index.
// "background: true" is mandatory and avoids downtime while the index builds.
// "sparse: true" is also mandatory because Parse Server uses sparse indexes.
coll.ensureIndex({ username: 1 }, { background: true, unique: true, sparse: true });
// Create the email index.
// "background: true" is still mandatory.
// "sparse: true" is also mandatory both because Parse Server uses sparse indexes, and because email addresses are not required by the Parse API.
coll.ensureIndex({ email: 1 }, { background: true, unique: true, sparse: true });
```
There are some issues you may run into during this process:
## Mongo complains that the index already exists, but with different options
In this case, you will need to remove the incorrect index. If your app relies on the existence of the index in order to be performant, you can create a new index, with "-1" for the direction of the field, so that it counts as different options. Then, drop the conflicting index, and create the unique index.
## There is already non-unique data in the username or email field
This is possible if you have explicitly set some user's emails to null. If this is bogus data, and those null fields should be unset, you can unset the null emails with this command. If your app relies on the difference between null and unset emails, you will need to upgrade your app to treat null and unset emails the same before building the index and upgrading to Parse Server 2.3.0.
```js
coll.update({ email: { $exists: true, $eq: null } }, { $unset: { email: '' } }, { multi: true })
```
## There is already non-unique data in the username or email field, and it's not nulls
This is possible due to a race condition in previous versions of Parse Server. If you have this problem, it is unlikely that you have a lot of rows with duplicate data. We recommend you clean up the data manually, by removing or modifying the offending rows.
This command, can be used to find the duplicate data:
```js
coll.aggregate([
{$match: {"username": {"$ne": null}}},
{$group: {_id: "$username", uniqueIds: {$addToSet: "$_id"}, count: {$sum: 1}}},
{$match: {count: {"$gt": 1}}},
{$project: {id: "$uniqueIds", username: "$_id", _id : 0} },
{$unwind: "$id" },
{$out: '_duplicates'} // Save the list of duplicates to a new, "_duplicates" collection. Remove this line to just output the list.
], {allowDiskUse:true})
```
-226
View File
@@ -1,226 +0,0 @@
# Upgrading Parse Server to version 3.0.0
parse-server 3.0.0 comes also with the JS SDK version 2.0 which requires a migration. Follow the migration guide [here](https://github.com/parse-community/Parse-SDK-JS/blob/master/2.0.0.md).
With the 3.0.0, parse-server has completely revamped it's cloud code interface. Gone are the backbone style calls, welcome promises and async/await.
In order to leverage those new nodejs features, you'll need to run at least node 8.10. We've dropped the support of node 6 a few months ago, so if you haven't made the change yet, now would be a really good time to take the plunge.
## Migrating Cloud Code Hooks
### Synchronous validations:
```js
// before
Parse.Cloud.beforeSave('MyClassName', function(request, response) {
if (!passesValidation(request.object)) {
response.error('Ooops something went wrong');
} else {
response.success();
}
});
// after
Parse.Cloud.beforeSave('MyClassName', (request) => {
if (!passesValidation(request.object)) {
throw 'Ooops something went wrong';
}
});
```
All methods are wrapped in promises, so you can freely `throw` `Error`, `Parse.Error` or `string` to mark an error.
### Asynchronous validations:
For asynchronous code, you can use promises or async / await.
Consider the following beforeSave call that would replace the contents of a fileURL with a proper copy of the image as a Parse.File.
```js
// before
Parse.Cloud.beforeSave('Post', function(request, response) {
Parse.Cloud.httpRequest({
url: request.object.get('fileURL'),
success: function(contents) {
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
file.save({
success: function() {
request.object.set('file', file);
response.success();
},
error: response.error
});
},
error: response.error
});
});
```
As we can see the current way, with backbone style callbacks is quite tough to read and maintain.
It's also not really trivial to handle errors, as you need to pass the response.error to each error handlers.
Now it can be modernized with promises:
```js
// after (with promises)
Parse.Cloud.beforeSave('MyClassName', (request) => {
return Parse.Cloud.httpRequest({
url: request.object.get('fileURL')
}).then((contents) => {
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
request.object.set('file', file);
return file.save();
});
});
```
And you can even make it better with async/await.
```js
// after with async/await
Parse.Cloud.beforeSave('MyClassName', async (request) => {
const contents = await Parse.Cloud.httpRequest({
url: request.object.get('fileURL')
});
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
request.object.set('file', file);
await file.save();
});
```
## Aborting hooks and functions
In order to abort a `beforeSave` or any hook, you now need to throw an error:
```js
// after with async/await
Parse.Cloud.beforeSave('MyClassName', async (request) => {
// valid, will result in a Parse.Error(SCRIPT_FAILED, 'Something went wrong')
throw 'Something went wrong'
// also valid, will fail with Parse.Error(SCRIPT_FAILED, 'Something else went wrong')
throw new Error('Something else went wrong')
// using a Parse.Error is also valid
throw new Parse.Error(1001, 'My error')
});
```
## Migrating Functions
Cloud Functions can be migrated the same way as cloud code hooks.
In functions, the response object is not passed anymore, as it is in cloud code hooks
Continuing with the image downloader example:
```js
// before
Parse.Cloud.define('downloadImage', function(request, response) {
Parse.Cloud.httpRequest({
url: request.params.url,
success: function(contents) {
const file = new Parse.File(request.params.name, { base64: contents.buffer.toString('base64') });
file.save({
success: function() {
response.success(file);
},
error: response.error
});
},
error: response.error
});
});
```
You would call this method with:
```js
Parse.Cloud.run('downloadImage',{
url: 'https://example.com/file',
name: 'my-file'
});
```
To migrate this function you would follow the same practices as the ones before, and we'll jump right away to the async/await implementation:
```js
// after with async/await
Parse.Cloud.define('downloadImage', async (request) => {
const {
url, name
} = request.params;
const response = await Parse.Cloud.httpRequest({ url });
const file = new Parse.File(name, { base64: response.buffer.toString('base64') });
await file.save();
return file;
});
```
## Migrating jobs
As with hooks and functions, jobs don't have a status object anymore.
The message method has been moved to the request object.
```js
// before
Parse.Cloud.job('downloadImageJob', function(request, status) {
var query = new Parse.Query('ImagesToDownload');
query.find({
success: function(images) {
var done = 0;
for (var i = 0; i<images.length; i++) {
var image = images[i];
status.message('Doing '+image.get('url'));
Parse.Cloud.httpRequest({
url: image.get('url'),
success: function(contents) {
status.message('Got '+image.get('url'));
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
file.save({
success: function() {
status.message('Saved '+image.get('url'));
done++;
if (done == images.length) {
status.success();
}
},
error: function() {
response.message('Error '+image.get('url'));
done++;
if (done == images.length) {
status.error();
}
}
});
},
error: status.error
});
}
}
});
});
```
```js
Parse.Cloud.job('downloadImageJob', async function(request) {
const query = new Parse.Query('ImagesToDownload');
const images = await query.find();
const promises = images.map(async (image) => {
request.message('Doing ' + image.get('url'));
const contents = await Parse.Cloud.httpRequest({
url: image.get('url')
});
request.message('Got ' + image.get('url'));
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
await file.save();
request.message('Saved ' + image.get('url'));
});
await Promise.all(promises);
});
```
As you can see the new implementation is more concise, easier to read and maintain.
If you encounter a problem or discover an issue with this guide, or with any Parse Community project, feel free to [reach out on github](https://github.com/parse-community/parse-server/issues/new/choose)
+78
View File
@@ -0,0 +1,78 @@
# Parse Server 6 Migration Guide <!-- omit in toc -->
This document only highlights specific changes that require a longer explanation. For a full list of changes in Parse Server 6 please refer to the [changelog](https://github.com/parse-community/parse-server/blob/alpha/CHANGELOG.md).
---
- [Incompatible git protocol with Node 14](#incompatible-git-protocol-with-node-14)
- [Import Statement](#import-statement)
- [Asynchronous Initialization](#asynchronous-initialization)
---
## Incompatible git protocol with Node 14
Parse Server 6 uses the Node Package Manger (npm) package lock file version 2. While version 2 is supposed to be backwards compatible with version 1, you may still encounter errors due to incompatible git protocols that cannot be interpreted correctly by npm bundled with Node 14.
If you are encountering issues installing Parse Server on Node 14 because of dependency references in the package lock file using the `ssh` protocol, configure git to use the `https` protocol instead:
```
sudo git config --system url."https://github".insteadOf "ssh://git@github"
```
Alternatively you could manually replace the dependency URLs in the package lock file.
⚠️ You could also delete the package lock file and recreate it with Node 14. Keep in mind that doing so you are not using an official version of Parse Server anymore. You may be using dependencies that have not been tested as part of the Parse Server release process.
## Import Statement
The import and initialization syntax has been simplified with more intuitive naming and structure.
*Parse Server 5:*
```js
// Returns a Parse Server instance
const ParseServer = require('parse-server');
// Returns a Parse Server express middleware
const { ParseServer } = require('parse-server');
```
*Parse Server 6:*
```js
// Both return a Parse Server instance
const ParseServer = require('parse-server');
const { ParseServer } = require('parse-server');
```
To get the express middleware in Parse Server 6, configure the Parse Server instance, start Parse Server and use its `app` property. See [Asynchronous Initialization](#asynchronous-initialization) for more details.
## Asynchronous Initialization
Previously, it was possible to mount Parse Server before it was fully started up and ready to receive requests. This could result in undefined behavior, such as Parse Objects could be saved before Cloud Code was registered. To prevent this, Parse Server 6 requires to be started asynchronously before being mounted.
*Parse Server 5:*
```js
// 1. Import Parse Server
const { ParseServer } = require('parse-server');
// 2. Create a Parse Server instance as express middleware
const server = new ParseServer(config);
// 3. Mount express middleware
app.use("/parse", server);
```
*Parse Server 6:*
```js
// 1. Import Parse Server
const ParseServer = require('parse-server');
// 2. Create a Parse Server instance
const server = new ParseServer(config);
// 3. Start up Parse Server asynchronously
await server.start();
// 4. Mount express middleware
app.use("/parse", server.app);
```
+186 -8
View File
@@ -2,7 +2,19 @@
## Table of Contents <!-- omit in toc -->
- [Contributing](#contributing)
- [Issue vs. Pull Request](#issue-vs-pull-request)
- [Scope](#scope)
- [Templates](#templates)
- [Why Contributing?](#why-contributing)
- [Contribution FAQs](#contribution-faqs)
- [Reviewer Role](#reviewer-role)
- [Review Feedback](#review-feedback)
- [Merge Readiness](#merge-readiness)
- [Review Validity](#review-validity)
- [Code Ownership](#code-ownership)
- [Access Permissions](#access-permissions)
- [New Private Repository](#new-private-repository)
- [New Public Repository](#new-public-repository)
- [Environment Setup](#environment-setup)
- [Recommended Tools](#recommended-tools)
- [Setting up your local machine](#setting-up-your-local-machine)
@@ -20,13 +32,21 @@
- [Parse Error](#parse-error)
- [Parse Server Configuration](#parse-server-configuration)
- [Pull Request](#pull-request)
- [Commit Message](#commit-message)
- [Breaking Change](#breaking-change)
- [Merging](#merging)
- [Breaking Change](#breaking-change-1)
- [Reverting](#reverting)
- [Security Vulnerability](#security-vulnerability)
- [Local Testing](#local-testing)
- [Merging](#merging-1)
- [Releasing](#releasing)
- [General Considerations](#general-considerations)
- [Major Release / Long-Term-Support](#major-release--long-term-support)
- [Preparing Release](#preparing-release)
- [Publishing Release (forward-merge):](#publishing-release-forward-merge)
- [Publishing Hotfix (back-merge):](#publishing-hotfix-back-merge)
- [Publishing Major Release (Yearly Release)](#publishing-major-release-yearly-release)
- [Versioning](#versioning)
- [Code of Conduct](#code-of-conduct)
@@ -44,6 +64,30 @@ When you are ready to code, you can find more information about opening a pull r
Whether this is your first contribution or you are already an experienced contributor, the Parse Community has your back – don't hesitate to ask for help!
### Issue vs. Pull Request
An issue is required to be linked in every pull request. We understand that no-one likes to create an issue for something that appears to be a simple pull request, but here is why this is beneficial for everyone:
- An issue get more visibility than a pull request as issues can be pinned, receive bounties and it is primarily the issue list that people browse through rather than the more technical pull request list. Visibility is a key aspect so others can weigh in on issues and contribute their opinion.
- The discussion in the issue is different from the discussion in the pull request. The issue discussion is focused on the issue and how to address it, whereas the discussion in the pull request is focused on a specific implemention. An issue may even have multiple pull requests because either the issue requires multiple implementations or multiple pull requests are opened to compare and test different approaches to later decide for one.
- High-level conceptual discussions about the issue should be still available, even if a pull request is closed because its appraoch was discarded. If these discussions are in the pull request instead, they can easily become fragmented over multiple pull requests and issues, which can make it very hard to make sense of all aspects of an issue.
### Scope
An issue and pull request must limit its scope on a distinct issue. Pull requests can only contain changes that are required to address the scoped issue. While it may seem quick and easy to add unrelated changes to the pull request, it can cause singificant complications after merging. Some of the reasons are:
- A pull request corresponds to a single changelog entry. A changelog entry should not describe multiple unrelated changes in one entry for better readability.
- A pull request creates a distinct commit; having an individual commit for each limited scope makes it easier for others to go back in the commit history and debug. Bugs are generally more difficult to identify and fix if there are various unrelated changes merged at once.
- If a pull request needs to be reverted, unrelated changes will be reverted as well. That makes it more complex and time consuming to revert, having to consider its effects and possibly publishing a broken release or requiring a follow-up pull request with code manipulation.
### Templates
You are required to use and completely fill out the templates for new issues and pull requests. We understand that no-one enjoys filling out forms, but here is why this is beneficial for everyone:
- It may take you 30 seconds longer, but will save even more time for everyone else trying to understand your issue.
- It helps to fix issues and merge pull requests faster as reviewers spend less time trying to understand your issue.
- It makes investigations easier when others try to understand your issue and code changes made even years later.
## Why Contributing?
Buy cheap, buy twice. What? No, this is not the Economics 101 class, but the same is true for contributing.
@@ -65,6 +109,70 @@ Consider the benefits you get:
Most importantly, with every contribution you improve your skills so that future contributions take even less time and you get all the benefits above for free — easy choice, right?
## Contribution FAQs
### Reviewer Role
> *Instead of writing review comments back-and-forth, why doesn't the reviewer just write the code themselves?*
A reviewer is already helping you to make a code contribution through their review. A reviewer *may* even help you to write code by actually writing it for you, but is not obliged to do so.
GitHub allows reviewers to suggest and write code changes as part of the review feedback. These code suggestions are likely to contain mistakes due to the lack of code syntax checks when writing code directly on GitHub. You should therefore always review these suggestions before accepting them, ideally in an IDE. If you merge a code suggestion and the CI then fails, take another look at the code change before asking the reviewer for help.
### Review Feedback
> *It takes too much effort to incorporate the review feedback, why why can't you just merge my pull request?*
If you are a new contributor, it's naturally a learning experience for you and therefore takes longer. We welcome contributors of any experience levels and gladly support you in getting familiar with the code base and our quality standards and contribution requirements. In return we expect you to be open to and appreciative of the reviewers' feedback.
In a large pull request, it can be a significant effort to bring it over the finish line. Luckily this is a collaborative environment and others are free to jump in to contribute to the pull request to share the effort. You can either give others access to your fork or they can open their own pull request based on your previous work.
If you are out of resources stay calm, explain your personal constraints (expertise or time) and ask for help. Wasting time by complaining about the amount of review comments will neither use your own time in a meaningful way, nor the time of others who read your complaint.
This is a collaborative enviroment in which everyone works on a common goal - to get a pull request ready for merging. Reviewers are working *with* you to get your pull request ready, *not against you*.
**❗️ Always be mindful that the reviewers' efforts are an integral part of code contribution. Their review is as important as your written code and their review time is a valuable as your coding time.**
### Merge Readiness
> *The feature already works, why do you request more changes instead of just merging my pull request?*
A feature may work for your own use case or in your own environment, but that doesn't necessarily mean that it's ready for merging. Aside from code quality and code style requirements, reviewers also review based on strategic and architectural considerations. It's often easy to just get a feature to work, but it needs to be also maintained in the future, robust therefore well tested and validated, intuitive for other developers to use, well documented, and not cause a forseeable breaking change in the near future.
### Review Validity
> *The reviewer has never worked on the issue and was never part of any previous discussion, why would I care about their opinion?*
It's contrary to an open, collaborative environment to expect others to be involved in an issue or discussion since its beginning. Such a mindset would close out any new views, which are important for a differentiated discussion.
> *The reviewer doesn't have any expertise in that matter, why would I care about their opinion?*
Your arguments must focus on the issue, not on your assumption of someone else's personal experience. We will take immediate and appropriate action in case of personal attacks, regardless of your previous contributions. Personal attacks are not permissible. If you became a victim of personal attacks, you can privately [report](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam) the GitHub comment to the Parse Platform PMC.
### Code Ownership
> *Can I open a new pull request based on another author's pull request?*
If your pull request contains work from someone else then you are required to get their permission to use their work in your pull request. Please make sure to observe the [license](LICENSE) for more details. In addition, as an appreciative gesture you should clearly mention that your pull request is based on another pull request with a link in the top-most comment of your pull request. To avoid this issue we encourage contributors to collaborate on a single pull request to preserve the commit history and clearly identify each author's contribution. To do so, you can review the other author's pull request and submit your code suggestions, or ask the original author to grant you write access to their repository to also be able to make commits directly to their pull request.
### Access Permissions
> *Can I get write access to the repository to make changes faster?*
Keeping our products safe and secure is one of your top priorities. Our security policy mandates that write access to repositories is only provided to as few people as necessary. All usual contributions can be made via public pull requests. If you think you need write access, contact the repository team and explain in detail what the constraint is that you are trying to overcome. We want to make contributing for you as easy as possible. If there are any bottlenecks that are slowing you down we are happy to receive your feedback to see where we can improve.
### New Private Repository
> *Can I get a new private repository within the Parse Platform organization to work on some stuff?*
Private repositories are not provided unless there is a significant constraint or requirement that makes it necessary. For example, when collaborating on fixing a security vulnerability we provide private repositories to allow collaborators to share sensitive information within a select group.
### New Public Repository
> *Can I get a new public repository within the Parse Platform organization to work on some stuff?*
First of all, we appreciate your contribution. In rare cases, where we consider it beneficial to the advancement of the repository, a new public repository for a specific purpose may be provided, for example for increased visibility or to provide the organization's GitHub ressources. In other cases, we encourage you to start your contribution in a personal repository of your own GitHub account, and later transfer it to the Parse Platform organization. We will be happy to assist you in the repository transfer.
## Environment Setup
### Recommended Tools
@@ -134,7 +242,11 @@ Once you have babel running in watch mode, you can start making changes to parse
If your pull request introduces a change that may affect the storage or retrieval of objects, you may want to make sure it plays nice with Postgres.
* Run the tests against the postgres database with `PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly`. You'll need to have postgres running on your machine and setup [appropriately](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) or use [`Docker`](#run-a-parse-postgres-with-docker).
* You'll need to have postgres running on your machine and setup [appropriately](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) or use [`Docker`](#postgres-with-docker)
* Run the tests against the postgres database with:
```
PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly
```
* The Postgres adapter has a special debugger that traces all the sql commands. You can enable it with setting the environment variable `PARSE_SERVER_LOG_LEVEL=debug`
* If your feature is intended to only work with MongoDB, you should disable PostgreSQL-specific tests with:
@@ -156,10 +268,10 @@ If your pull request introduces a change that may affect the storage or retrieva
#### Postgres with Docker
[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:
[PostGIS images (select one with v2.2 or higher) on docker hub](https://hub.docker.com/r/postgis/postgis) is based off of the official [postgres](https://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.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
docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:16-3.4-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:
@@ -167,7 +279,7 @@ To stop the Postgres instance:
docker stop parse-postgres
```
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:
You can also use the [postgis/postgis:16-3.4-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
@@ -301,6 +413,8 @@ Introducing new [Parse Server configuration][config] parameters requires the fol
## Pull Request
### Commit Message
For release automation, the title of pull requests needs to be written in a defined syntax. We loosely follow the [Conventional Commits](https://www.conventionalcommits.org) specification, which defines this syntax:
```
@@ -381,28 +495,92 @@ If the commit reverts a previous commit, use the prefix `revert:`, followed by t
This reverts commit 1234567890abcdef.
```
### Security Vulnerability
#### Local Testing
Fixes for securify vulnerabilities are developed in private forks with a closed audience, inaccessible to the public. A current GitHub limitation does not allow to run CI tests on pull requests in private forks. Whether a pull requests fully passes all CI tests can only be determined by publishing the fix as a public pull request and running the CI. This means the fix and implicitly information about the vulnerabilty are made accessible to the public. This increases the risk that a vulnerability fix is published, but then cannot be merged immediately due to a CI issue. To mitigate that risk, before publishing a vulnerability fix, the following tests needs to be run locally and pass:
- `npm run test` (MongoDB)
- `npm run test` (Postgres)
- `npm run madge:circular` (circular dependencies)
- `npm run lint` (Lint)
- `npm run definitions` (Parse Server options definitions)
#### Merging
A current GitHub limitation does not allow to customize the commit message when merging pull requests of a private fork that was created to fix a security vulnerabilty. Our release automation framework demands a specific commit message syntax which therefore cannot be met. This prohibits to follow the process that GitHub suggest, which is to merge a pull request from a private fork directly to a public branch. Instead, after [local testing](#local-testing), a public pull request needs to be created with the code fix copied over from the private pull request.
This creates a risk that a vulnerability is indirectly disclosed by publishing a pull request with the fix, but the fix cannot be merged due to a CI issue. To mitigate that risk, the pull request title and description should be kept marginal or generic, not hiting to a vulnerabilty or giving any details about the vulnerabilty, until the pull request has been successfully merged.
## Releasing
### General Considerations
- The `package-lock.json` file has to be deleted and recreated by npm from scratch in regular intervals using the `npm i` command. It is not enough to only update the file via automated security pull requests (e.g. dependabot, snyk), that can create inconsistencies between sub-devependencies of a dependency and increase the chances of vulnerabilities. The file should be recreated once every release cycle which is usually monthly.
- The `package-lock.json` file has to be deleted and recreated by npm from scratch in regular intervals using the `npm i` command. It is not enough to only update the file via automated security pull requests (e.g. dependabot, snyk), that can create inconsistencies between sub-dependencies of a dependency and increase the chances of vulnerabilities. The file should be recreated once every release cycle which is usually monthly.
### Major Release / Long-Term-Support
Long-Term-Support (LTS) is provided for the previous Parse Server major version. For example, Parse Server 4.x will receive security updates until Parse Server 5.x is superseded by Parse Server 6.x and becomes the new LTS version. While the current major version is published on branch `release`, a LTS version is published on branch `release-#.x.x`, for example `release-4.x.x` for the Parse Server 4.x LTS branch.
While the current major version is published on branch `release`, a Long-Term-Support (LTS) version is published on branch `release-#.x.x`, for example `release-4.x.x` for the Parse Server 4.x LTS branch.
#### Preparing Release
### Preparing Release
The following changes are done in the `alpha` branch, before publishing the last `beta` version that will eventually become the major release. This way the changes trickle naturally through all branches and code consistency is ensured among branches.
- Make sure all [deprecations](https://github.com/parse-community/parse-server/blob/alpha/DEPRECATIONS.md) are reflected in code, old code is removed and the deprecations table is updated.
- Add the future LTS branch `release-#.x.x` to the branch list in [release.config.js](https://github.com/parse-community/parse-server/blob/alpha/release.config.js) so that the branch will later be recognized for release automation.
#### Publishing Release
### Publishing Release (forward-merge):
1. Create new temporary branch `build` on branch `beta`.
2. Create PR to merge `build` into `release`:
- PR title: `build: release`
- PR description: (leave empty)
3. Resolve any conflicts:
- For conflicts regarding the package version in `package.json` and `package-lock.json` it doesn't matter which version is chosen, as the version will be set by auto-release in a commit after merging. However, for both files the same version should be chosen when resolving the conflict.
4. Merge PR with a "merge commit", do not "squash and merge":
- Commit message: (use PR title)
- Description: (leave empty)
5. Wait for GitHub Action `release-automated` to finish:
- If GitHub Action fails, investigate why; manual correction may be needed.
6. Pull all remote branches into local branches.
7. Delete temporary branch `build`.
8. Create new temporary branch `build` on branch `alpha`.
9. Create PR to merge `build` into `beta`:
- PR title: `build: release`
- PR description: (leave empty)
8. Repeat steps 3-7 for PR from step 9.
### Publishing Hotfix (back-merge):
1. Create PR to merge hotfix PR into `release`:
- Merge PR following the same rules as any PR would be merged into the working branch `alpha`.
2. Wait for GitHub Action `release-automated` to finish:
- GitHub Action will fail with error `! [rejected] HEAD -> beta (non-fast-forward)`; this is expected as auto-release currently cannot fully handle back-merging; docker will not publish the new release, so this has to be done manually using the GitHub workflow `release-manual-docker` and entering the version tag that has been created by auto-release.
3. Pull all remote branches into local branches.
4. Create a new temporary branch `backmerge` on branch `release`.
5. Create PR to merge `backmerge` into `beta`:
- PR title: `refactor: <commit-summary>` where `<commit-summary>` is the commit summary of step 1. The commit type needs to be `refactor`, otherwise the commit will show in the changelog of the `release` branch, once the `beta` branch is merged into release; this would a duplicate entry because the same changelog entry has already been generated when the PR was merged into the `release` branch in step 1.
- PR description: (leave empty)
6. Resolve any conflicts:
- During back-merging, usually all changes are preserved; current changes come from the hotfix in the `release` branch, the incoming changes come from the `beta` branch usually being ahead of the `release` branch. This makes back-merging so complex and bug-prone and is the main reason why it should be avoided if possible.
7. Merge PR with "squash and merge", do not do a "merge commit":
- Commit message: (use PR title)
- Description: (leave empty)
ℹ️ Merging this PR will not trigger a release; the back-merge will not appear in changelogs of the `beta`, `alpha` branches; the back-merged fix will be an undocumented change of these branches' next releases; if necessary, the change needs to be added manually to the pre-release changelogs *after* the next pre-releases.
8. Delete temporary branch `backmerge`.
10. Create a new temporary branch `backmerge` on branch `beta`.
11. Repeat steps 4-8 to merge PR into `alpha`.
⚠️ Long-term-support branches are excluded from the processes above and handled individually as they do not have pre-releases branches and are not considered part of the current codebase anymore. It may be necessary to significantly adapt a PR for a LTS branch due to the differences in codebase and CI tests. This adaption should be done in advance before merging any related PR, especially for security fixes, as to not publish a vulnerability while it may still take significant time to adapt the fix for the older codebase of a LTS branch.
### Publishing Major Release (Yearly Release)
1. Create LTS branch `release-#.x.x` off the latest version tag on `release` branch.
2. Create temporary branch `build-release` off branch `beta` and create a pull request with `release` as the base branch.
3. Merge branch `build-release` into `release`. Given that there will be breaking changes, a new major release will be created. In the unlikely case that there have been no breaking changes between the previous major release and the upcoming release, a major version increment has to be triggered manually. See the docs of the release automation framework for how to do that.
4. Add newly created LTS branch `release-#.x.x` from step 1 to [Snyk](https://snyk.io) so that Snyk opens pull requests for the LTS branch; remove previously existing LTS branch `release-#.x.x` from Snyk.
## Versioning
+10 -7
View File
@@ -4,13 +4,16 @@ The following is a list of deprecations, according to the [Deprecation Policy](h
| ID | Change | Issue | Deprecation [ℹ️][i_deprecation] | Planned Removal [ℹ️][i_removal] | Status [ℹ️][i_status] | Notes |
|--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
| DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
| DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
| DEPPS8 | Login with expired 3rd party authentication token defaults to `false` | [#7079](https://github.com/parse-community/parse-server/pull/7079) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
| DEPPS9 | Rename LiveQuery `fields` option to `keys` | [#8389](https://github.com/parse-community/parse-server/issues/8389) | 6.0.0 (2023) | 7.0.0 (2024) | removed | - |
| DEPPS10 | Config option `encodeParseObjectInCloudFunction` defaults to `true` | [#8634](https://github.com/parse-community/parse-server/issues/8634) | 6.2.0 (2023) | 8.0.0 (2025) | deprecated | - |
[i_deprecation]: ## "The version and date of the deprecation."
[i_removal]: ## "The version and date of the planned removal."
+19 -21
View File
@@ -1,10 +1,13 @@
############################################################
# Build stage
############################################################
FROM node:lts-alpine as build
FROM node:20.14.0-alpine3.20 AS build
RUN apk --no-cache add \
build-base \
git \
python3
RUN apk update; \
apk add git;
WORKDIR /tmp
# Copy package.json first to benefit from layer caching
@@ -13,37 +16,32 @@ COPY package*.json ./
# Copy src to have config files for install
COPY . .
# Clean npm cache; added to fix an issue with the install process
RUN npm cache clean --force
# Install all dependencies
RUN npm ci
# Run build steps
RUN npm run build
# Install without scripts
RUN npm ci --omit=dev --ignore-scripts \
# Copy production node_modules aside for later
&& cp -R node_modules prod_node_modules \
# Install all dependencies
&& npm ci \
# Run build steps
&& npm run build
############################################################
# Release stage
############################################################
FROM node:lts-alpine as release
RUN apk update; \
apk add git;
FROM node:20.14.0-alpine3.20 AS release
VOLUME /parse-server/cloud /parse-server/config
WORKDIR /parse-server
# Copy build stage folders
COPY --from=build /tmp/prod_node_modules /parse-server/node_modules
COPY --from=build /tmp/lib lib
COPY package*.json ./
# Clean npm cache; added to fix an issue with the install process
RUN npm cache clean --force
RUN npm ci --production --ignore-scripts
COPY bin bin
COPY public_html public_html
COPY views views
COPY --from=build /tmp/lib lib
RUN mkdir -p logs && chown -R node: logs
ENV PORT=1337
+167 -25
View File
@@ -1,34 +1,176 @@
BSD License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
For Parse Server software
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright (c) 2015-present, Parse, LLC. All rights reserved.
1. Definitions.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
* Neither the name Parse nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
-----
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
As of April 5, 2017, Parse, LLC has transferred this code to the parse-community organization, and will no longer be contributing to or distributing this code.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
+10
View File
@@ -0,0 +1,10 @@
Parse Server
Copyright 2015-present Parse Platform
This product includes software developed at Parse Platform.
www.parseplatform.org
---
As of April 5, 2017, Parse, LLC has transferred this code to the Parse Platform organization, and will no longer be contributing to or distributing this code.
-37
View File
@@ -1,37 +0,0 @@
Additional Grant of Patent Rights Version 2
"Software" means the Parse Server software distributed by Parse, LLC.
Parse, LLC. ("Parse") hereby grants to each recipient of the Software
("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
(subject to the termination provision below) license under any Necessary
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
transfer the Software. For avoidance of doubt, no license is granted under
Parse’s rights in any patent claims that are infringed by (i) modifications
to the Software made by you or any third party or (ii) the Software in
combination with any software or other technology.
The license granted hereunder will terminate, automatically and without notice,
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
directly or indirectly, or take a direct financial interest in, any Patent
Assertion: (i) against Parse or any of its subsidiaries or corporate
affiliates, (ii) against any party if such Patent Assertion arises in whole or
in part from any software, technology, product or service of Parse or any of
its subsidiaries or corporate affiliates, or (iii) against any party relating
to the Software. Notwithstanding the foregoing, if Parse or any of its
subsidiaries or corporate affiliates files a lawsuit alleging patent
infringement against you in the first instance, and you respond by filing a
patent infringement counterclaim in that lawsuit against that party that is
unrelated to the Software, the license granted hereunder will not terminate
under section (i) of this paragraph due to such counterclaim.
A "Necessary Claim" is a claim of a patent owned by Parse that is
necessarily infringed by the Software standing alone.
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
or contributory infringement or inducement to infringe any patent, including a
cross-claim or counterclaim.
-----
As of April 5, 2017, Parse, LLC has transferred this code to the parse-community organization, and will no longer be contributing to or distributing this code.
+95 -79
View File
@@ -1,15 +1,17 @@
![parse-repository-header-server](https://user-images.githubusercontent.com/5673677/138278489-7d0cebc5-1e31-4d3c-8ffb-53efcda6f29d.png)
---
[![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)
[![Build Status](https://github.com/parse-community/parse-server/workflows/ci/badge.svg?branch=beta)](https://github.com/parse-community/parse-server/actions?query=workflow%3Aci+branch%3Abeta)
[![Build Status](https://github.com/parse-community/parse-server/workflows/ci/badge.svg?branch=release)](https://github.com/parse-community/parse-server/actions?query=workflow%3Aci+branch%3Arelease)
[![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)
[![Coverage](https://codecov.io/github/parse-community/parse-server/branch/alpha/graph/badge.svg)](https://app.codecov.io/github/parse-community/parse-server/tree/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,_16,_17,_18-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,_5.1,_5.2-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)
[![Node Version](https://img.shields.io/badge/nodejs-18,_20-green.svg?logo=node.js&style=flat)](https://nodejs.org)
[![MongoDB Version](https://img.shields.io/badge/mongodb-4.2,_4.4,_5,_6,_7-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com)
[![Postgres Version](https://img.shields.io/badge/postgresql-13,_14,_15,_16-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org)
[![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)
@@ -17,7 +19,6 @@
[![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]
[![License][license-svg]][license-link]
[![Forum](https://img.shields.io/discourse/https/community.parseplatform.org/topics.svg)](https://community.parseplatform.org/c/parse-server)
[![Twitter](https://img.shields.io/twitter/follow/ParsePlatform.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=ParsePlatform)
[![Chat](https://img.shields.io/badge/Chat-Join!-%23fff?style=social&logo=slack)](https://chat.parseplatform.org)
@@ -32,16 +33,14 @@ The full documentation for Parse Server is available in the [wiki](https://githu
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)](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)](https://opencollective.com/parse-server/contribute/bronze-sponsor-10559)
---
- [Flavors \& Branches](#flavors--branches)
- [Long Term Support](#long-term-support)
- [Getting Started](#getting-started)
- [Running Parse Server](#running-parse-server)
- [Compatibility](#compatibility)
@@ -55,9 +54,12 @@ A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who
- [Running Parse Server elsewhere](#running-parse-server-elsewhere)
- [Sample Application](#sample-application)
- [Parse Server + Express](#parse-server--express)
- [Parse Server Health](#parse-server-health)
- [Status Values](#status-values)
- [Configuration](#configuration)
- [Basic Options](#basic-options)
- [Client Key Options](#client-key-options)
- [Access Scopes](#access-scopes)
- [Email Verification and Password Reset](#email-verification-and-password-reset)
- [Password and Account Policy](#password-and-account-policy)
- [Custom Routes](#custom-routes)
@@ -89,13 +91,24 @@ A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who
- [Using automatically generated operations](#using-automatically-generated-operations)
- [Customizing your GraphQL Schema](#customizing-your-graphql-schema)
- [Learning more](#learning-more)
- [Upgrading to 3.0.0](#upgrading-to-300)
- [Want to ride the bleeding edge?](#want-to-ride-the-bleeding-edge)
- [Contributing](#contributing)
- [Contributors](#contributors)
- [Sponsors](#sponsors)
- [Backers](#backers)
# Flavors & Branches
Parse Server is available in different flavors on different branches:
- The main branches are [release][log_release], [beta][log_beta] and [alpha][log_alpha]. See the [changelog overview](CHANGELOG.md) for details.
- The long-term-support (LTS) branches are named `release-<version>.x.x`, for example `release-5.x.x`. LTS branches do not have pre-release branches.
## Long Term Support
Long-Term-Support (LTS) is provided for the previous Parse Server major version. For example, Parse Server 5.x will receive security updates until Parse Server 6.x is superseded by Parse Server 7.x and becomes the new LTS version. While the current major version is published on branch `release`, a LTS version is published on branch `release-#.x.x`, for example `release-5.x.x` for the Parse Server 5.x LTS branch.
⚠️ LTS versions are provided to help you transition as soon as possible to the current major version. While we aim to fix security vulnerabilities in the LTS version, our main focus is on developing the current major version and preparing the next major release. Therefore we may leave certain vulnerabilities up to the community to fix. Search for [pull requests with the specific LTS base branch](https://github.com/parse-community/parse-server/pulls?q=is%3Aopen+is%3Apr+base%3Arelease-5.x.x) to see the current open vulnerabilities for that LTS branch.
# Getting Started
The fastest and easiest way to get started is to run MongoDB and Parse Server locally.
@@ -116,35 +129,31 @@ Parse Server is continuously tested with the most recent releases of Node.js to
| Version | Latest Version | End-of-Life | Compatible |
|------------|----------------|-------------|------------|
| Node.js 12 | 12.22.11 | April 2022 | ✅ Yes |
| Node.js 14 | 14.19.1 | April 2023 | ✅ Yes |
| Node.js 16 | 16.14.2 | April 2024 | ✅ Yes |
| Node.js 17 | 17.9.0 | June 2022 | ✅ Yes |
| Node.js 18 | 18.1.0 | April 2025 | ✅ Yes |
| Node.js 18 | 18.20.0 | April 2025 | ✅ Yes |
| Node.js 20 | 20.12.0 | April 2026 | ✅ 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.
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 [MongoDB lifecycle schedule](https://www.mongodb.com/support-policy/lifecycles) and only test against versions that are officially supported and have not reached their end-of-life date. MongoDB "rapid releases" are ignored as these are considered pre-releases of the next major version.
| Version | Latest Version | End-of-Life | Compatible |
|-------------|----------------|-------------|------------|
| MongoDB 4.0 | 4.0.28 | April 2022 | ✅ Yes |
| MongoDB 4.2 | 4.2.19 | TBD | ✅ Yes |
| MongoDB 4.4 | 4.4.13 | TBD | ✅ Yes |
| MongoDB 5.0 | 5.0.6 | TBD | ✅ Yes |
| MongoDB 5.1 | 5.1.1 | TBD | ✅ Yes |
| MongoDB 5.2 | 5.2.1 | TBD | ✅ Yes |
| Version | Latest Version | End-of-Life | Compatible |
| ----------- | -------------- | ------------- | ---------- |
| MongoDB 4.2 | 4.2.25 | April 2023 | ✅ Yes |
| MongoDB 4.4 | 4.4.29 | February 2024 | ✅ Yes |
| MongoDB 5 | 5.0.26 | October 2024 | ✅ Yes |
| MongoDB 6 | 6.0.14 | July 2025 | ✅ Yes |
| MongoDB 7 | 7.0.8 | TDB | ✅ Yes |
#### PostgreSQL
Parse Server is continuously tested with the most recent releases of PostgreSQL and PostGIS to ensure compatibility, using [PostGIS docker images](https://registry.hub.docker.com/r/postgis/postgis/tags?page=1&ordering=last_updated). We follow the [PostgreSQL support schedule](https://www.postgresql.org/support/versioning) and [PostGIS support schedule](https://www.postgis.net/eol_policy/) and only test against versions that are officially supported and have not reached their end-of-life date. Due to the extensive PostgreSQL support duration of 5 years, Parse Server drops support if a version is older than 3.5 years and a newer version has been available for at least 2.5 years.
Parse Server is continuously tested with the most recent releases of PostgreSQL and PostGIS to ensure compatibility, using [PostGIS docker images](https://registry.hub.docker.com/r/postgis/postgis/tags?page=1&ordering=last_updated). We follow the [PostgreSQL support schedule](https://www.postgresql.org/support/versioning) and [PostGIS support schedule](https://www.postgis.net/eol_policy/) and only test against versions that are officially supported and have not reached their end-of-life date. Due to the extensive PostgreSQL support duration of 5 years, Parse Server drops support about 2 years before the official end-of-life date.
| Version | PostGIS Version | End-of-Life | Parse Server Support End | Compatible |
|-------------|-----------------|---------------|--------------------------|------------|
| 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 |
| Version | PostGIS Version | End-of-Life | Parse Server Support | Compatible |
|-------------|--------------------|---------------|----------------------|------------|
| Postgres 13 | 3.1, 3.2, 3.3, 3.4 | November 2025 | <= 6.x (2023) | ✅ Yes |
| Postgres 14 | 3.4 | November 2026 | <= 7.x (2024) | ✅ Yes |
| Postgres 15 | 3.4 | November 2027 | <= 8.x (2025) | ✅ Yes |
| Postgres 16 | 3.4 | November 2028 | <= 9.x (2026) | ✅ Yes |
### Locally
@@ -272,11 +281,11 @@ We have provided a basic [Node.js application](https://github.com/parse-communit
You can also create an instance of Parse Server, and mount it on a new or existing Express website:
```js
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
const express = require('express');
const ParseServer = require('parse-server').ParseServer;
const app = express();
var api = new ParseServer({
const server = new ParseServer({
databaseURI: 'mongodb://localhost:27017/dev', // Connection string for your MongoDB database
cloud: './cloud/main.js', // Path to your Cloud Code
appId: 'myAppId',
@@ -285,8 +294,11 @@ var api = new ParseServer({
serverURL: 'http://localhost:1337/parse' // Don't forget to change to https if needed
});
// Start server
await server.start();
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
app.use('/parse', server.app);
app.listen(1337, function() {
console.log('parse-server-example running on port 1337.');
@@ -295,6 +307,27 @@ app.listen(1337, function() {
For a full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations](http://parseplatform.org/parse-server/api/master/ParseServerOptions.html).
## Parse Server Health
Check the Parse Server health by sending a request to the `/parse/health` endpoint.
The response looks like this:
```json
{
"status": "ok"
}
```
### Status Values
| Value | Description |
|---------------|-----------------------------------------------------------------------------|
| `initialized` | The server has been created but the `start` method has not been called yet. |
| `starting` | The server is starting up. |
| `ok` | The server started and is running. |
| `error` | There was a startup error, see the logs for details. |
# Configuration
Parse Server can be configured using the following options. You may pass these as parameters when running a standalone `parse-server`, or by loading a configuration file in JSON format using `parse-server path/to/configuration.json`. If you're using Parse Server on Express, you may also pass these to the `ParseServer` object as options.
@@ -320,6 +353,17 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
* `restAPIKey`
* `dotNetKey`
## Access Scopes
| Scope | Internal data | Read-only data <sub>(1)</sub> | Custom data | Restricted by CLP, ACL | Key |
|----------------|---------------|-------------------------------|-------------|------------------------|---------------------|
| Internal | r/w | r/w | r/w | no | `maintenanceKey` |
| Master | -/- | r/- | r/w | no | `masterKey` |
| ReadOnlyMaster | -/- | r/- | r/- | no | `readOnlyMasterKey` |
| Session | -/- | r/- | r/w | yes | `sessionToken` |
<sub>(1) `Parse.Object.createdAt`, `Parse.Object.updatedAt`.</sub>
## Email Verification and Password Reset
Verifying user email addresses and enabling password reset via email requires an email adapter. There are many email adapters provided and maintained by the community. The following is an example configuration with an example email adapter. See the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) for more details and a full list of available options.
@@ -345,8 +389,10 @@ const server = ParseServer({
});
```
Offical email adapters maintained by Parse Platform:
- [parse-server-api-mail-adapter](https://github.com/parse-community/parse-server-api-mail-adapter) (localization, templates, universally supports any email provider)
Email adapters contributed by the community:
- [parse-server-api-mail-adapter](https://www.npmjs.com/package/parse-server-api-mail-adapter) (localization, templates, universally supports any email provider)
- [parse-smtp-template](https://www.npmjs.com/package/parse-smtp-template) (localization, templates)
- [parse-server-postmark-adapter](https://www.npmjs.com/package/parse-server-postmark-adapter)
- [parse-server-sendgrid-adapter](https://www.npmjs.com/package/parse-server-sendgrid-adapter)
@@ -377,7 +423,7 @@ const server = ParseServer({
},
// The password policy
passwordPolicy: {
passwordPolicy: {
// Enforce a password of at least 8 characters which contain at least 1 lower case, 1 upper case and 1 digit
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/,
// Do not allow the username as part of the password
@@ -418,7 +464,7 @@ const api = new ParseServer({
The above route can be invoked by sending a `GET` request to:
`https://[parseServerPublicUrl]/[parseMount]/[pagesEndpoint]/[appId]/[customRoute]`
The `handler` receives the `request` and returns a `custom_page.html` webpage from the `pages.pagesPath` directory as response. The advantage of building a custom route this way is that it automatically makes use of Parse Server's built-in capabilities, such as [page localization](#pages) and [dynamic placeholders](#dynamic-placeholders).
### Reserved Paths
@@ -449,7 +495,7 @@ The following paths are already used by Parse Server's built-in features and are
It’s possible to change the default pages of the app and redirect the user to another path or domain.
```js
var server = ParseServer({
const server = ParseServer({
...otherOptions,
customPages: {
@@ -506,7 +552,7 @@ Parse Server allows developers to choose from several options when hosting files
`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
**Caution, this is an experimental feature that may not be appropriate for production.**
This feature deduplicates identical requests that are received by Parse Server multiple times, typically due to network issues or network adapter access restrictions on mobile operating systems.
@@ -839,7 +885,7 @@ Then, create an `index.js` file with the following content:
```js
const express = require('express');
const { default: ParseServer, ParseGraphQLServer } = require('parse-server');
const { ParseServer, ParseGraphQLServer } = require('parse-server');
const app = express();
@@ -863,6 +909,7 @@ app.use('/parse', parseServer.app); // (Optional) Mounts the REST API
parseGraphQLServer.applyGraphQL(app); // Mounts the GraphQL API
parseGraphQLServer.applyPlayground(app); // (Optional) Mounts the GraphQL Playground - do NOT use in Production
await parseServer.start();
app.listen(1337, function() {
console.log('REST API running on http://localhost:1337/parse');
console.log('GraphQL API running on http://localhost:1337/graphql');
@@ -1104,37 +1151,9 @@ You also have a very powerful tool inside your GraphQL Playground. Please look a
Additionally, the [GraphQL Learn Section](https://graphql.org/learn/) is a very good source to learn more about the power of the GraphQL language.
# Upgrading to 3.0.0
Starting 3.0.0, parse-server uses the JS SDK version 2.0.
In short, parse SDK v2.0 removes the backbone style callbacks as well as the Parse.Promise object in favor of native promises.
All the Cloud Code interfaces also have been updated to reflect those changes, and all backbone style response objects are removed and replaced by Promise style resolution.
We have written up a [migration guide](3.0.0.md), hoping this will help you transition to the next major release.
# Want to ride the bleeding edge?
It is recommend to use builds deployed npm for many reasons, but if you want to use
the latest not-yet-released version of parse-server, you can do so by depending
directly on this branch:
```
npm install parse-community/parse-server.git#master
```
## Experimenting <!-- omit in toc -->
You can also use your own forks, and work in progress branches by specifying them:
```
npm install github:myUsername/parse-server#my-awesome-feature
```
And don't forget, if you plan to deploy it remotely, you should run `npm install` with the `--save` option.
# Contributing
We really want Parse to be yours, to see it grow and thrive in the open source community. Please see the [Contributing to Parse Server guide](CONTRIBUTING.md).
Please see the [Contributing Guide](CONTRIBUTING.md).
# Contributors
@@ -1183,10 +1202,7 @@ Support us with a monthly donation and help us continue our activities. [Become
<a href="https://opencollective.com/parse-server#backers" target="_blank"><img src="https://opencollective.com/parse-server/backers.svg?width=890" /></a>
-----
As of April 5, 2017, Parse, LLC has transferred this code to the parse-community organization, and will no longer be contributing to or distributing this code.
[license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg
[license-link]: LICENSE
[open-collective-link]: https://opencollective.com/parse-server
[log_release]: https://github.com/parse-community/parse-server/blob/release/changelogs/CHANGELOG_release.md
[log_beta]: https://github.com/parse-community/parse-server/blob/beta/changelogs/CHANGELOG_beta.md
[log_alpha]: https://github.com/parse-community/parse-server/blob/alpha/changelogs/CHANGELOG_alpha.md
File diff suppressed because it is too large Load Diff
+276
View File
@@ -1,3 +1,279 @@
# [7.2.0-beta.1](https://github.com/parse-community/parse-server/compare/7.1.0...7.2.0-beta.1) (2024-07-09)
### Bug Fixes
* Invalid push notification tokens are not cleaned up from database for FCM API v2 ([#9173](https://github.com/parse-community/parse-server/issues/9173)) ([284da09](https://github.com/parse-community/parse-server/commit/284da09f4546356b37511a589fb5f64a3efffe79))
### Features
* Add support for dot notation on array fields of Parse Object ([#9115](https://github.com/parse-community/parse-server/issues/9115)) ([cf4c880](https://github.com/parse-community/parse-server/commit/cf4c8807b9da87a0a5f9c94e5bdfcf17cda80cf4))
* Upgrade to @parse/push-adapter 6.4.0 ([#9182](https://github.com/parse-community/parse-server/issues/9182)) ([ef1634b](https://github.com/parse-community/parse-server/commit/ef1634bf1f360429108d29b08032fc7961ff96a1))
* Upgrade to Parse JS SDK 5.3.0 ([#9180](https://github.com/parse-community/parse-server/issues/9180)) ([dca187f](https://github.com/parse-community/parse-server/commit/dca187f91b93cbb362b22a3fb9ee38451799ff13))
# [7.1.0-beta.1](https://github.com/parse-community/parse-server/compare/7.0.0...7.1.0-beta.1) (2024-06-30)
### Bug Fixes
* `Parse.Cloud.startJob` and `Parse.Push.send` not returning status ID when setting Parse Server option `directAccess: true` ([#8766](https://github.com/parse-community/parse-server/issues/8766)) ([5b0efb2](https://github.com/parse-community/parse-server/commit/5b0efb22efe94c47f243cf8b1e6407ed5c5a67d3))
* `Required` option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations ([#8915](https://github.com/parse-community/parse-server/issues/8915)) ([907ad42](https://github.com/parse-community/parse-server/commit/907ad4267c228d26cfcefe7848b30ce85ba7ff8f))
* Facebook Limited Login not working due to incorrect domain in JWT validation ([#9122](https://github.com/parse-community/parse-server/issues/9122)) ([9d0bd2b](https://github.com/parse-community/parse-server/commit/9d0bd2badd6e5f7429d1af00b118225752e5d86a))
* Live query throws error when constraint `notEqualTo` is set to `null` ([#8835](https://github.com/parse-community/parse-server/issues/8835)) ([11d3e48](https://github.com/parse-community/parse-server/commit/11d3e484df862224c15d20f6171514948981ea90))
* Parse Server option `extendSessionOnUse` not working for session lengths < 24 hours ([#9113](https://github.com/parse-community/parse-server/issues/9113)) ([0a054e6](https://github.com/parse-community/parse-server/commit/0a054e6b541fd5ab470bf025665f5f7d2acedaa0))
* Rate limiting can fail when using Parse Server option `rateLimit.redisUrl` with clusters ([#8632](https://github.com/parse-community/parse-server/issues/8632)) ([c277739](https://github.com/parse-community/parse-server/commit/c27773962399f8e27691e3b8087e7e1d59516efd))
* SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) ([#9167](https://github.com/parse-community/parse-server/issues/9167)) ([2edf1e4](https://github.com/parse-community/parse-server/commit/2edf1e4c0363af01e97a7fbc97694f851b7d1ff3))
### Features
* Add `silent` log level for Cloud Code ([#8803](https://github.com/parse-community/parse-server/issues/8803)) ([5f81efb](https://github.com/parse-community/parse-server/commit/5f81efb42964c4c2fa8bcafee9446a0122e3ce21))
* Add server security check status `security.enableCheck` to Features Router ([#8679](https://github.com/parse-community/parse-server/issues/8679)) ([b07ec15](https://github.com/parse-community/parse-server/commit/b07ec153825882e97cc48dc84072c7f549f3238b))
* Prevent Parse Server start in case of unknown option in server configuration ([#8987](https://github.com/parse-community/parse-server/issues/8987)) ([8758e6a](https://github.com/parse-community/parse-server/commit/8758e6abb9dbb68757bddcbd332ad25100c24a0e))
* Upgrade to @parse/push-adapter 6.0.0 ([#9066](https://github.com/parse-community/parse-server/issues/9066)) ([18bdbf8](https://github.com/parse-community/parse-server/commit/18bdbf89c53a57648891ef582614ba7c2941e587))
* Upgrade to @parse/push-adapter 6.2.0 ([#9127](https://github.com/parse-community/parse-server/issues/9127)) ([ca20496](https://github.com/parse-community/parse-server/commit/ca20496f28e5ec1294a7a23c8559df82b79b2a04))
* Upgrade to Parse JS SDK 5.2.0 ([#9128](https://github.com/parse-community/parse-server/issues/9128)) ([665b8d5](https://github.com/parse-community/parse-server/commit/665b8d52d6cf5275179a5e1fb132c934edb53ecc))
# [7.0.0-beta.1](https://github.com/parse-community/parse-server/compare/6.5.0-beta.1...7.0.0-beta.1) (2024-03-19)
### Bug Fixes
* CacheAdapter does not connect when using a CacheAdapter with a JSON config ([#8633](https://github.com/parse-community/parse-server/issues/8633)) ([720d24e](https://github.com/parse-community/parse-server/commit/720d24e18540da35d50957f17be878316ec30318))
* Conditional email verification not working in some cases if `verifyUserEmails`, `preventLoginWithUnverifiedEmail` set to functions ([#8838](https://github.com/parse-community/parse-server/issues/8838)) ([8e7a6b1](https://github.com/parse-community/parse-server/commit/8e7a6b1480c0117e6c73e7adc5a6619115a04e85))
* Deny request if master key is not set in Parse Server option `masterKeyIps` regardless of ACL and CLP ([#8957](https://github.com/parse-community/parse-server/issues/8957)) ([a7b5b38](https://github.com/parse-community/parse-server/commit/a7b5b38418cbed9be3f4a7665f25b97f592663e1))
* Docker image not published to Docker Hub on new release ([#8905](https://github.com/parse-community/parse-server/issues/8905)) ([a2ac8d1](https://github.com/parse-community/parse-server/commit/a2ac8d133c71cd7b61e5ef59c4be915cfea85db6))
* Docker version releases by removing arm/v6 and arm/v7 support ([#8976](https://github.com/parse-community/parse-server/issues/8976)) ([1f62dd0](https://github.com/parse-community/parse-server/commit/1f62dd0f4e107b22a387692558a042ee26ce8703))
* GraphQL file upload fails in case of use of pointer or relation ([#8721](https://github.com/parse-community/parse-server/issues/8721)) ([1aba638](https://github.com/parse-community/parse-server/commit/1aba6382c873fb489d4a898d301e6da9fb6aa61b))
* Improve PostgreSQL injection detection; fixes security vulnerability [GHSA-6927-3vr9-fxf2](https://github.com/parse-community/parse-server/security/advisories/GHSA-6927-3vr9-fxf2) which affects Parse Server deployments using a Postgres database ([#8961](https://github.com/parse-community/parse-server/issues/8961)) ([cbefe77](https://github.com/parse-community/parse-server/commit/cbefe770a7260b54748a058b8a7389937dc35833))
* Incomplete user object in `verifyEmail` function if both username and email are changed ([#8889](https://github.com/parse-community/parse-server/issues/8889)) ([1eb95ae](https://github.com/parse-community/parse-server/commit/1eb95aeb41a96250e582d79a703f6adcb403c08b))
* Parse Server option `emailVerifyTokenReuseIfValid: true` generates new token on every email verification request ([#8885](https://github.com/parse-community/parse-server/issues/8885)) ([0023ce4](https://github.com/parse-community/parse-server/commit/0023ce448a5e9423337d0e1a25648bde1156bc95))
* Parse Server option `fileExtensions` default value rejects file extensions that are less than 3 or more than 4 characters long ([#8699](https://github.com/parse-community/parse-server/issues/8699)) ([2760381](https://github.com/parse-community/parse-server/commit/276038118377c2b22381bcd8d30337203822121b))
* Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) ([#9024](https://github.com/parse-community/parse-server/issues/9024)) ([9f6e342](https://github.com/parse-community/parse-server/commit/9f6e3429d3b326cf4e2994733c618d08032fac6e))
* Server crashes when receiving an array of `Parse.Pointer` in the request body ([#8784](https://github.com/parse-community/parse-server/issues/8784)) ([66e3603](https://github.com/parse-community/parse-server/commit/66e36039d8af654cfa0284666c0ddd94975dcb52))
* Username is `undefined` in email verification link on email change ([#8887](https://github.com/parse-community/parse-server/issues/8887)) ([e315c13](https://github.com/parse-community/parse-server/commit/e315c137bf41bedfa8f0df537f2c3f6ab45b7e60))
### Features
* Add `installationId` to arguments for `verifyUserEmails`, `preventLoginWithUnverifiedEmail` ([#8836](https://github.com/parse-community/parse-server/issues/8836)) ([a22dbe1](https://github.com/parse-community/parse-server/commit/a22dbe16d5ac0090608f6caaf0ebd134925b7fd4))
* Add `installationId`, `ip`, `resendRequest` to arguments passed to `verifyUserEmails` on verification email request ([#8873](https://github.com/parse-community/parse-server/issues/8873)) ([8adcbee](https://github.com/parse-community/parse-server/commit/8adcbee11283d3e95179ca2047e2615f52c18806))
* Add `Parse.User` as function parameter to Parse Server options `verifyUserEmails`, `preventLoginWithUnverifiedEmail` on login ([#8850](https://github.com/parse-community/parse-server/issues/8850)) ([972f630](https://github.com/parse-community/parse-server/commit/972f6300163b3cd7d95eeb95986e8322c95f821c))
* Add password validation via POST request for user with unverified email using master key and option `ignoreEmailVerification` ([#8895](https://github.com/parse-community/parse-server/issues/8895)) ([633a9d2](https://github.com/parse-community/parse-server/commit/633a9d25e4253e2125bc93c02ee8a37e0f5f7b83))
* Add support for MongoDB 7 ([#8761](https://github.com/parse-community/parse-server/issues/8761)) ([3de8494](https://github.com/parse-community/parse-server/commit/3de8494a221991dfd10a74e0a2dc89576265c9b7))
* Add support for MongoDB query comment ([#8928](https://github.com/parse-community/parse-server/issues/8928)) ([2170962](https://github.com/parse-community/parse-server/commit/2170962a50fa353ed85eda3f11dce7ee3647b087))
* Add support for Node 20, drop support for Node 14, 16 ([#8907](https://github.com/parse-community/parse-server/issues/8907)) ([ced4872](https://github.com/parse-community/parse-server/commit/ced487246ea0ef72a8aa014991f003209b34841e))
* Add support for Postgres 16 ([#8898](https://github.com/parse-community/parse-server/issues/8898)) ([99489b2](https://github.com/parse-community/parse-server/commit/99489b22e4f0982e6cb39992974b51aa8d3a31e4))
* Allow `Parse.Session.current` on expired session token instead of throwing error ([#8722](https://github.com/parse-community/parse-server/issues/8722)) ([f9dde4a](https://github.com/parse-community/parse-server/commit/f9dde4a9f8a90c63f71172c9bc515b0f6c6d2e4a))
* Deprecation DEPPS5: Config option `allowClientClassCreation` defaults to `false` ([#8849](https://github.com/parse-community/parse-server/issues/8849)) ([29624e0](https://github.com/parse-community/parse-server/commit/29624e0fae17161cd412ae58d35a195cfa286cad))
* Deprecation DEPPS6: Authentication adapters disabled by default ([#8858](https://github.com/parse-community/parse-server/issues/8858)) ([0cf58eb](https://github.com/parse-community/parse-server/commit/0cf58eb8d60c8e5f485764e154f3214c49eee430))
* Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax ([#8855](https://github.com/parse-community/parse-server/issues/8855)) ([4e6a375](https://github.com/parse-community/parse-server/commit/4e6a375b5184ae0f7aa256a921eca4021c609435))
* Deprecation DEPPS8: Parse Server option `allowExpiredAuthDataToken` defaults to `false` ([#8860](https://github.com/parse-community/parse-server/issues/8860)) ([e29845f](https://github.com/parse-community/parse-server/commit/e29845f8dacac09ce3093d75c0d92330c24389e8))
* Deprecation DEPPS9: LiveQuery `fields` option is renamed to `keys` ([#8852](https://github.com/parse-community/parse-server/issues/8852)) ([38983e8](https://github.com/parse-community/parse-server/commit/38983e8e9b5cdbd006f311a2338103624137d013))
* Node process exits with error code 1 on uncaught exception to allow custom uncaught exception handling ([#8894](https://github.com/parse-community/parse-server/issues/8894)) ([70c280c](https://github.com/parse-community/parse-server/commit/70c280ca578ff28b5acf92f37fbe06d42a5b34ca))
* Switch GraphQL server from Yoga v2 to Apollo v4 ([#8959](https://github.com/parse-community/parse-server/issues/8959)) ([105ae7c](https://github.com/parse-community/parse-server/commit/105ae7c8a57d5a650b243174a80c26bf6db16e28))
* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740))
* Upgrade to Parse JS SDK 5 ([#9022](https://github.com/parse-community/parse-server/issues/9022)) ([ad4aa83](https://github.com/parse-community/parse-server/commit/ad4aa83983205a0e27639f6ee6a4a5963b67e4b8))
### Performance Improvements
* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522))
### BREAKING CHANGES
* The Parse Server option `allowClientClassCreation` defaults to `false`. ([29624e0](29624e0))
* A request using the master key will now be rejected as unauthorized if the IP from which the request originates is not set in the Parse Server option `masterKeyIps`, even if the request does not require the master key permission, for example for a public object in a public class class. ([a7b5b38](a7b5b38))
* Node process now exits with code 1 on uncaught exceptions, enabling custom handlers that were blocked by Parse Server's default behavior of re-throwing errors. This change may lead to automatic process restarts by the environment, unlike before. ([70c280c](70c280c))
* Authentication adapters are disabled by default; to use an authentication adapter it needs to be explicitly enabled in the Parse Server authentication adapter option `auth.<provider>.enabled: true` ([0cf58eb](0cf58eb))
* Parse Server option `allowExpiredAuthDataToken` defaults to `false`; a 3rd party authentication token will be validated every time the user tries to log in and the login will fail if the token has expired; the effect of this change may differ for different authentication adapters, depending on the token lifetime and the token refresh logic of the adapter ([e29845f](e29845f))
* LiveQuery `fields` option is renamed to `keys` ([38983e8](38983e8))
* Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'` ([4e6a375](4e6a375))
* Removes support for Node 14 and 16 ([ced4872](ced4872))
* Removes support for Postgres 11 and 12 ([99489b2](99489b2))
* The `Parse.User` passed as argument if `verifyUserEmails` is set to a function is renamed from `user` to `object` for consistency with invocations of `verifyUserEmails` on signup or login; the user object is not a plain JavaScript object anymore but an instance of `Parse.User` ([8adcbee](8adcbee))
* `Parse.Session.current()` no longer throws an error if the session token is expired, but instead returns the session token with its expiration date to allow checking its validity ([f9dde4a](f9dde4a))
* `Parse.Query` no longer supports the BSON type `code`; although this feature was never officially documented, its removal is announced as a breaking change to protect deployments where it might be in use. ([3de8494](3de8494))
# [6.5.0-beta.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-beta.1) (2023-11-16)
### Bug Fixes
* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3))
* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a))
* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c))
* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1))
### Features
* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29))
* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620))
* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d))
* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d))
# [6.4.0-beta.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-beta.1) (2023-09-16)
### Bug Fixes
* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b))
* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49))
* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec))
* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64))
### Features
* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a))
* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298))
* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589))
### Performance Improvements
* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd))
# [6.3.0-beta.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.3.0-beta.1) (2023-06-10)
### Bug Fixes
* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804))
* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394))
* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4))
* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b))
* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e))
* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae))
### Features
* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029))
* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab))
* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d))
* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e))
* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e))
* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761))
### Reverts
* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff))
# [6.1.0-beta.2](https://github.com/parse-community/parse-server/compare/6.1.0-beta.1...6.1.0-beta.2) (2023-05-01)
### Bug Fixes
* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))
### Features
* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))
# [6.1.0-beta.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-beta.1) (2023-03-02)
### Bug Fixes
* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))
### Features
* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
# [6.0.0-beta.1](https://github.com/parse-community/parse-server/compare/5.4.0...6.0.0-beta.1) (2023-01-31)
### Bug Fixes
* `ParseServer.verifyServerUrl` may fail if server response headers are missing; remove unnecessary logging ([#8391](https://github.com/parse-community/parse-server/issues/8391)) ([1c37a7c](https://github.com/parse-community/parse-server/commit/1c37a7cd0715949a70b220a629071c7dab7d5e7b))
* Cloud Code trigger `beforeSave` does not work with `Parse.Role` ([#8320](https://github.com/parse-community/parse-server/issues/8320)) ([f29d972](https://github.com/parse-community/parse-server/commit/f29d9720e9b37918fd885c97a31e34c42750e724))
* ES6 modules do not await the import of Cloud Code files ([#8368](https://github.com/parse-community/parse-server/issues/8368)) ([a7bd180](https://github.com/parse-community/parse-server/commit/a7bd180cddd784c8735622f22e012c342ad535fb))
* Nested objects are encoded incorrectly for MongoDB ([#8209](https://github.com/parse-community/parse-server/issues/8209)) ([1412666](https://github.com/parse-community/parse-server/commit/1412666f75829612de6fb9d7ccae35761c9b75cb))
* Parse Server option `masterKeyIps` does not include localhost by default for IPv6 ([#8322](https://github.com/parse-community/parse-server/issues/8322)) ([ab82635](https://github.com/parse-community/parse-server/commit/ab82635b0d4cf323a07ddee51fee587b43dce95c))
* Rate limiter may reject requests that contain a session token ([#8399](https://github.com/parse-community/parse-server/issues/8399)) ([c114dc8](https://github.com/parse-community/parse-server/commit/c114dc8831055d74187b9dfb4c9eeb558520237c))
* Remove Node 12 and Node 17 support ([#8279](https://github.com/parse-community/parse-server/issues/8279)) ([2546cc8](https://github.com/parse-community/parse-server/commit/2546cc8572bea6610cb9b3c7401d9afac0e3c1d6))
* Schema without class level permissions may cause error ([#8409](https://github.com/parse-community/parse-server/issues/8409)) ([aa2cd51](https://github.com/parse-community/parse-server/commit/aa2cd51b703388d925e4572e5c2b2d883c68e49c))
* The client IP address may be determined incorrectly in some cases; this fixes a security vulnerability in which the Parse Server option `masterKeyIps` may be circumvented, see [GHSA-vm5r-c87r-pf6x](https://github.com/parse-community/parse-server/security/advisories/GHSA-vm5r-c87r-pf6x) ([#8372](https://github.com/parse-community/parse-server/issues/8372)) ([892040d](https://github.com/parse-community/parse-server/commit/892040dc2f82a3e2abe2824e4b553521b6f894de))
* Throwing error in Cloud Code Triggers `afterLogin`, `afterLogout` crashes server ([#8280](https://github.com/parse-community/parse-server/issues/8280)) ([130d290](https://github.com/parse-community/parse-server/commit/130d29074e3f763460e5685d0b9059e5a333caff))
### Features
* Access the internal scope of Parse Server using the new `maintenanceKey`; the internal scope contains unofficial and undocumented fields (prefixed with underscore `_`) which are used internally by Parse Server; you may want to manipulate these fields for out-of-band changes such as data migration or correction tasks; changes within the internal scope of Parse Server may happen at any time without notice or changelog entry, it is therefore recommended to look at the source code of Parse Server to understand the effects of manipulating internal fields before using the key; it is discouraged to use the `maintenanceKey` for routine operations in a production environment; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) ([#8212](https://github.com/parse-community/parse-server/issues/8212)) ([f3bcc93](https://github.com/parse-community/parse-server/commit/f3bcc9365cd6f08b0a32c132e8e5ff6d1b650863))
* Adapt `verifyServerUrl` for new asynchronous Parse Server start-up states ([#8366](https://github.com/parse-community/parse-server/issues/8366)) ([ffa4974](https://github.com/parse-community/parse-server/commit/ffa4974158615fbff4a2692b9db41dcb50d3f77b))
* Add `ParseQuery.watch` to trigger LiveQuery only on update of specific fields ([#8028](https://github.com/parse-community/parse-server/issues/8028)) ([fc92faa](https://github.com/parse-community/parse-server/commit/fc92faac75107b3392eeddd916c4c5b45e3c5e0c))
* Add Node 19 support ([#8363](https://github.com/parse-community/parse-server/issues/8363)) ([a4990dc](https://github.com/parse-community/parse-server/commit/a4990dcd29abcb4442f3c424aff482a0a116160f))
* Add option to change the log level of the logs emitted by triggers ([#8328](https://github.com/parse-community/parse-server/issues/8328)) ([8f3b694](https://github.com/parse-community/parse-server/commit/8f3b694e39d4a966567e50dbea4d62e954fa5c06))
* Add request rate limiter based on IP address ([#8174](https://github.com/parse-community/parse-server/issues/8174)) ([6c79f6a](https://github.com/parse-community/parse-server/commit/6c79f6a69e25e47846e3b0685d6bdfd6b91086b1))
* Asynchronous initialization of Parse Server ([#8232](https://github.com/parse-community/parse-server/issues/8232)) ([99fcf45](https://github.com/parse-community/parse-server/commit/99fcf45e55c368de2345b0c4d780e70e0adf0e15))
* Improve authentication adapter interface to support multi-factor authentication (MFA), authentication challenges, and provide a more powerful interface for writing custom authentication adapters ([#8156](https://github.com/parse-community/parse-server/issues/8156)) ([5bbf9ca](https://github.com/parse-community/parse-server/commit/5bbf9cade9a527787fd1002072d4013ab5d8db2b))
* Reduce Docker image size by improving stages ([#8359](https://github.com/parse-community/parse-server/issues/8359)) ([40810b4](https://github.com/parse-community/parse-server/commit/40810b48ebde8b1f21d2448a3a4de0585b1b5e34))
* Remove deprecation `DEPPS1`: Native MongoDB syntax in aggregation pipeline ([#8362](https://github.com/parse-community/parse-server/issues/8362)) ([d0d30c4](https://github.com/parse-community/parse-server/commit/d0d30c4f1394f563724644a8fc81734be538a2c0))
* Remove deprecation `DEPPS2`: Config option `directAccess` defaults to true ([#8284](https://github.com/parse-community/parse-server/issues/8284)) ([f535ee6](https://github.com/parse-community/parse-server/commit/f535ee6ec2abba63f702127258ca49fa5b4e08c9))
* Remove deprecation `DEPPS3`: Config option `enforcePrivateUsers` defaults to `true` ([#8283](https://github.com/parse-community/parse-server/issues/8283)) ([ed499e3](https://github.com/parse-community/parse-server/commit/ed499e32a21bab9a874a9e5367dc71248ce836c4))
* Remove deprecation `DEPPS4`: Remove convenience method for http request `Parse.Cloud.httpRequest` ([#8287](https://github.com/parse-community/parse-server/issues/8287)) ([2d79c08](https://github.com/parse-community/parse-server/commit/2d79c0835b6a9acaf20d5c943d9b4619bb96831c))
* Remove support for MongoDB 4.0 ([#8292](https://github.com/parse-community/parse-server/issues/8292)) ([37245f6](https://github.com/parse-community/parse-server/commit/37245f62ce83516b6b95a54b850f0274ef680478))
* Restrict use of `masterKey` to localhost by default ([#8281](https://github.com/parse-community/parse-server/issues/8281)) ([6c16021](https://github.com/parse-community/parse-server/commit/6c16021a1f03a70a6d9e68cb64df362d07f3b693))
* Upgrade Node Package Manager lock file `package-lock.json` to version 2 ([#8285](https://github.com/parse-community/parse-server/issues/8285)) ([ee72467](https://github.com/parse-community/parse-server/commit/ee7246733d63e4bda20401f7b00262ff03299f20))
* Upgrade Redis 3 to 4 ([#8293](https://github.com/parse-community/parse-server/issues/8293)) ([7d622f0](https://github.com/parse-community/parse-server/commit/7d622f06a4347e0ad2cba9a4ec07d8d4fb0f67bc))
* Upgrade Redis 3 to 4 for LiveQuery ([#8333](https://github.com/parse-community/parse-server/issues/8333)) ([b2761fb](https://github.com/parse-community/parse-server/commit/b2761fb3786b519d9bbcf35be54309d2d35da1a9))
* Upgrade to Parse JavaScript SDK 4 ([#8332](https://github.com/parse-community/parse-server/issues/8332)) ([9092874](https://github.com/parse-community/parse-server/commit/9092874a9a482a24dfdce1dce56615702999d6b8))
* Write log entry when request with master key is rejected as outside of `masterKeyIps` ([#8350](https://github.com/parse-community/parse-server/issues/8350)) ([e22b73d](https://github.com/parse-community/parse-server/commit/e22b73d4b700c8ff745aa81726c6680082294b45))
### BREAKING CHANGES
* The Docker image does not contain the git dependency anymore; if you have been using git as a transitive dependency it now needs to be explicitly installed in your Docker file, for example with `RUN apk --no-cache add git` (#8359) ([40810b4](40810b4))
* Fields in the internal scope of Parse Server (prefixed with underscore `_`) are only returned using the new `maintenanceKey`; previously the `masterKey` allowed reading of internal fields; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) for a comparison of the keys' access permissions (#8212) ([f3bcc93](f3bcc93))
* The method `ParseServer.verifyServerUrl` now returns a promise instead of a callback. ([ffa4974](ffa4974))
* The MongoDB aggregation pipeline requires native MongoDB syntax instead of the custom Parse Server syntax; for example pipeline stage names require a leading dollar sign like `$match` and the MongoDB document ID is referenced using `_id` instead of `objectId` (#8362) ([d0d30c4](d0d30c4))
* The mechanism to determine the client IP address has been rewritten; to correctly determine the IP address it is now required to set the Parse Server option `trustProxy` accordingly if Parse Server runs behind a proxy server, see the express framework's [trust proxy](https://expressjs.com/en/guide/behind-proxies.html) setting (#8372) ([892040d](892040d))
* The Node Package Manager lock file `package-lock.json` is upgraded to version 2; while it is backwards with version 1 for the npm installer, consider this if you run any non-npm analysis tools that use the lock file (#8285) ([ee72467](ee72467))
* This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232) ([99fcf45](99fcf45))
* Nested objects are now properly stored in the database using JSON serialization; previously, due to a bug only top-level objects were serialized, but nested objects were saved as raw JSON; for example, a nested `Date` object was saved as a JSON object like `{ "__type": "Date", "iso": "2020-01-01T00:00:00.000Z" }` instead of its serialized representation `2020-01-01T00:00:00.000Z` (#8209) ([1412666](1412666))
* The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283) ([ed499e3](ed499e3))
* This release restricts the use of `masterKey` to localhost by default; if you are using Parse Dashboard on a different server to connect to Parse Server you need to add the IP address of the server that hosts Parse Dashboard to this option (#8281) ([6c16021](6c16021))
* This release upgrades to Redis 4; if you are using the Redis cache adapter with Parse Server then this is a breaking change as the Redis client options have changed; see the [Redis migration guide](https://github.com/redis/node-redis/blob/redis%404.0.0/docs/v3-to-v4.md) for more details (#8293) ([7d622f0](7d622f0))
* This release removes support for MongoDB 4.0; the new minimum supported MongoDB version is 4.2. which also removes support for the deprecated MongoDB MMAPv1 storage engine ([37245f6](37245f6))
* Throwing an error in Cloud Code Triggers `afterLogin`, `afterLogout` returns a rejected promise; in previous releases it crashed the server if you did not handle the error on the Node.js process level; consider adapting your code if your app currently handles these errors on the Node.js process level with `process.on('unhandledRejection', ...)` ([130d290](130d290))
* Config option `directAccess` defaults to true; set this to `false` in environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`. ([f535ee6](f535ee6))
* The convenience method for HTTP requests `Parse.Cloud.httpRequest` is removed; use your preferred 3rd party library for making HTTP requests ([2d79c08](2d79c08))
* This release removes Node 12 and Node 17 support ([2546cc8](2546cc8))
# [5.4.0-beta.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.4.0-beta.1) (2022-10-29)
### Bug Fixes
* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) [skip release] ([#8187](https://github.com/parse-community/parse-server/issues/8187)) ([8c8ec71](https://github.com/parse-community/parse-server/commit/8c8ec715739e0f851338cfed794409ebac66c51b))
* brute force guessing of user sensitive data via search patterns (GHSA-2m6g-crv8-p3c6) ([#8146](https://github.com/parse-community/parse-server/issues/8146)) [skip release] ([4c0c7c7](https://github.com/parse-community/parse-server/commit/4c0c7c77b76257878b9bcb05ff9de01c9d790262))
* certificate in Apple Game Center auth adapter not validated [skip release] ([#8058](https://github.com/parse-community/parse-server/issues/8058)) ([75af9a2](https://github.com/parse-community/parse-server/commit/75af9a26cc8e9e88a33d1e452c93a0ee6e509f17))
* graphQL query ignores condition `equalTo` with value `false` ([#8032](https://github.com/parse-community/parse-server/issues/8032)) ([7f5a15d](https://github.com/parse-community/parse-server/commit/7f5a15d5df0dfa3515e9f73709d6a49663545f9b))
* internal indices for classes `_Idempotency` and `_Role` are not protected in defined schema ([#8121](https://github.com/parse-community/parse-server/issues/8121)) ([c16f529](https://github.com/parse-community/parse-server/commit/c16f529f74f92154401bf662f634b3c5fa45e18e))
* invalid file request not properly handled [skip release] ([#8062](https://github.com/parse-community/parse-server/issues/8062)) ([4c9e956](https://github.com/parse-community/parse-server/commit/4c9e95674ad081f13062e8cd30b77b1962d5df57))
* liveQuery with `containedIn` not working when object field is an array ([#8128](https://github.com/parse-community/parse-server/issues/8128)) ([1d9605b](https://github.com/parse-community/parse-server/commit/1d9605bc93009263d3811df4d4249034ba6eb8c4))
* protected fields exposed via LiveQuery (GHSA-crrq-vr9j-fxxh) [skip release] ([#8076](https://github.com/parse-community/parse-server/issues/8076)) ([9fd4516](https://github.com/parse-community/parse-server/commit/9fd4516cde5c742f9f29dd05468b4a43a85639a6))
* push notifications `badge` doesn't update with Installation beforeSave trigger ([#8162](https://github.com/parse-community/parse-server/issues/8162)) ([3c75c2b](https://github.com/parse-community/parse-server/commit/3c75c2ba4851fae96a8c19b11a3efde03816c9a1))
* query aggregation pipeline cannot handle value of type `Date` when `directAccess: true` ([#8167](https://github.com/parse-community/parse-server/issues/8167)) ([e424137](https://github.com/parse-community/parse-server/commit/e4241374061caef66538de15112fb6bbafb1f5bb))
* relation constraints in compound queries `Parse.Query.or`, `Parse.Query.and` not working ([#8203](https://github.com/parse-community/parse-server/issues/8203)) ([28f0d26](https://github.com/parse-community/parse-server/commit/28f0d2667787d2ac68726607b811d6f0ef62b9f1))
* security upgrade undici from 5.6.0 to 5.8.0 ([#8108](https://github.com/parse-community/parse-server/issues/8108)) ([4aa016b](https://github.com/parse-community/parse-server/commit/4aa016b7322467422b9fdf05d8e29b9ecf910da7))
* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) [skip release] ([#8238](https://github.com/parse-community/parse-server/issues/8238)) ([c03908f](https://github.com/parse-community/parse-server/commit/c03908f74e5c9eed834874a89df6c89c1a1e849f))
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) [skip release] ([#8180](https://github.com/parse-community/parse-server/issues/8180)) ([37fed30](https://github.com/parse-community/parse-server/commit/37fed3062ccc3ef1dfd49a9fc53318e72b3e4aff))
* sorting by non-existing value throws `INVALID_SERVER_ERROR` on Postgres ([#8157](https://github.com/parse-community/parse-server/issues/8157)) ([3b775a1](https://github.com/parse-community/parse-server/commit/3b775a1fb8a1878714e3451191438963d688f1b0))
* updating object includes unchanged keys in client response for certain key types ([#8159](https://github.com/parse-community/parse-server/issues/8159)) ([37af1d7](https://github.com/parse-community/parse-server/commit/37af1d78fce5a15039ffe3af7b323c1f1e8582fc))
### Features
* add convenience access to Parse Server configuration in Cloud Code via `Parse.Server` ([#8244](https://github.com/parse-community/parse-server/issues/8244)) ([9f11115](https://github.com/parse-community/parse-server/commit/9f111158edf7fd57a65db0c4f9244b37e58cf293))
* add option to change the default value of the `Parse.Query.limit()` constraint ([#8152](https://github.com/parse-community/parse-server/issues/8152)) ([0388956](https://github.com/parse-community/parse-server/commit/038895680894984e569dff54bf5c7b31094f3891))
* add support for MongoDB 6 ([#8242](https://github.com/parse-community/parse-server/issues/8242)) ([aba0081](https://github.com/parse-community/parse-server/commit/aba0081ce1a166a93de57f3928c19a05562b5cc1))
* add support for Postgres 15 ([#8215](https://github.com/parse-community/parse-server/issues/8215)) ([2feb6c4](https://github.com/parse-community/parse-server/commit/2feb6c46080946c984daa351187fa07cd582355d))
* liveQuery support for unsorted distance queries ([#8221](https://github.com/parse-community/parse-server/issues/8221)) ([0f763da](https://github.com/parse-community/parse-server/commit/0f763da17d646b2fec2cd980d3857e46072a8a07))
# [5.3.0-beta.1](https://github.com/parse-community/parse-server/compare/5.2.1...5.3.0-beta.1) (2022-06-17)
+382
View File
@@ -1,3 +1,385 @@
# [7.2.0](https://github.com/parse-community/parse-server/compare/7.1.0...7.2.0) (2024-07-09)
### Bug Fixes
* Invalid push notification tokens are not cleaned up from database for FCM API v2 ([#9173](https://github.com/parse-community/parse-server/issues/9173)) ([284da09](https://github.com/parse-community/parse-server/commit/284da09f4546356b37511a589fb5f64a3efffe79))
### Features
* Add support for dot notation on array fields of Parse Object ([#9115](https://github.com/parse-community/parse-server/issues/9115)) ([cf4c880](https://github.com/parse-community/parse-server/commit/cf4c8807b9da87a0a5f9c94e5bdfcf17cda80cf4))
* Upgrade to @parse/push-adapter 6.4.0 ([#9182](https://github.com/parse-community/parse-server/issues/9182)) ([ef1634b](https://github.com/parse-community/parse-server/commit/ef1634bf1f360429108d29b08032fc7961ff96a1))
* Upgrade to Parse JS SDK 5.3.0 ([#9180](https://github.com/parse-community/parse-server/issues/9180)) ([dca187f](https://github.com/parse-community/parse-server/commit/dca187f91b93cbb362b22a3fb9ee38451799ff13))
# [7.1.0](https://github.com/parse-community/parse-server/compare/7.0.0...7.1.0) (2024-06-30)
### Bug Fixes
* `Parse.Cloud.startJob` and `Parse.Push.send` not returning status ID when setting Parse Server option `directAccess: true` ([#8766](https://github.com/parse-community/parse-server/issues/8766)) ([5b0efb2](https://github.com/parse-community/parse-server/commit/5b0efb22efe94c47f243cf8b1e6407ed5c5a67d3))
* `Required` option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations ([#8915](https://github.com/parse-community/parse-server/issues/8915)) ([907ad42](https://github.com/parse-community/parse-server/commit/907ad4267c228d26cfcefe7848b30ce85ba7ff8f))
* Facebook Limited Login not working due to incorrect domain in JWT validation ([#9122](https://github.com/parse-community/parse-server/issues/9122)) ([9d0bd2b](https://github.com/parse-community/parse-server/commit/9d0bd2badd6e5f7429d1af00b118225752e5d86a))
* Live query throws error when constraint `notEqualTo` is set to `null` ([#8835](https://github.com/parse-community/parse-server/issues/8835)) ([11d3e48](https://github.com/parse-community/parse-server/commit/11d3e484df862224c15d20f6171514948981ea90))
* Parse Server option `extendSessionOnUse` not working for session lengths < 24 hours ([#9113](https://github.com/parse-community/parse-server/issues/9113)) ([0a054e6](https://github.com/parse-community/parse-server/commit/0a054e6b541fd5ab470bf025665f5f7d2acedaa0))
* Rate limiting can fail when using Parse Server option `rateLimit.redisUrl` with clusters ([#8632](https://github.com/parse-community/parse-server/issues/8632)) ([c277739](https://github.com/parse-community/parse-server/commit/c27773962399f8e27691e3b8087e7e1d59516efd))
* SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) ([#9167](https://github.com/parse-community/parse-server/issues/9167)) ([2edf1e4](https://github.com/parse-community/parse-server/commit/2edf1e4c0363af01e97a7fbc97694f851b7d1ff3))
### Features
* Add `silent` log level for Cloud Code ([#8803](https://github.com/parse-community/parse-server/issues/8803)) ([5f81efb](https://github.com/parse-community/parse-server/commit/5f81efb42964c4c2fa8bcafee9446a0122e3ce21))
* Add server security check status `security.enableCheck` to Features Router ([#8679](https://github.com/parse-community/parse-server/issues/8679)) ([b07ec15](https://github.com/parse-community/parse-server/commit/b07ec153825882e97cc48dc84072c7f549f3238b))
* Prevent Parse Server start in case of unknown option in server configuration ([#8987](https://github.com/parse-community/parse-server/issues/8987)) ([8758e6a](https://github.com/parse-community/parse-server/commit/8758e6abb9dbb68757bddcbd332ad25100c24a0e))
* Upgrade to @parse/push-adapter 6.0.0 ([#9066](https://github.com/parse-community/parse-server/issues/9066)) ([18bdbf8](https://github.com/parse-community/parse-server/commit/18bdbf89c53a57648891ef582614ba7c2941e587))
* Upgrade to @parse/push-adapter 6.2.0 ([#9127](https://github.com/parse-community/parse-server/issues/9127)) ([ca20496](https://github.com/parse-community/parse-server/commit/ca20496f28e5ec1294a7a23c8559df82b79b2a04))
* Upgrade to Parse JS SDK 5.2.0 ([#9128](https://github.com/parse-community/parse-server/issues/9128)) ([665b8d5](https://github.com/parse-community/parse-server/commit/665b8d52d6cf5275179a5e1fb132c934edb53ecc))
# [7.0.0](https://github.com/parse-community/parse-server/compare/6.4.0...7.0.0) (2024-03-19)
### Bug Fixes
* CacheAdapter does not connect when using a CacheAdapter with a JSON config ([#8633](https://github.com/parse-community/parse-server/issues/8633)) ([720d24e](https://github.com/parse-community/parse-server/commit/720d24e18540da35d50957f17be878316ec30318))
* Conditional email verification not working in some cases if `verifyUserEmails`, `preventLoginWithUnverifiedEmail` set to functions ([#8838](https://github.com/parse-community/parse-server/issues/8838)) ([8e7a6b1](https://github.com/parse-community/parse-server/commit/8e7a6b1480c0117e6c73e7adc5a6619115a04e85))
* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3))
* Deny request if master key is not set in Parse Server option `masterKeyIps` regardless of ACL and CLP ([#8957](https://github.com/parse-community/parse-server/issues/8957)) ([a7b5b38](https://github.com/parse-community/parse-server/commit/a7b5b38418cbed9be3f4a7665f25b97f592663e1))
* Docker image not published to Docker Hub on new release ([#8905](https://github.com/parse-community/parse-server/issues/8905)) ([a2ac8d1](https://github.com/parse-community/parse-server/commit/a2ac8d133c71cd7b61e5ef59c4be915cfea85db6))
* Docker version releases by removing arm/v6 and arm/v7 support ([#8976](https://github.com/parse-community/parse-server/issues/8976)) ([1f62dd0](https://github.com/parse-community/parse-server/commit/1f62dd0f4e107b22a387692558a042ee26ce8703))
* GraphQL file upload fails in case of use of pointer or relation ([#8721](https://github.com/parse-community/parse-server/issues/8721)) ([1aba638](https://github.com/parse-community/parse-server/commit/1aba6382c873fb489d4a898d301e6da9fb6aa61b))
* Improve PostgreSQL injection detection; fixes security vulnerability [GHSA-6927-3vr9-fxf2](https://github.com/parse-community/parse-server/security/advisories/GHSA-6927-3vr9-fxf2) which affects Parse Server deployments using a Postgres database ([#8961](https://github.com/parse-community/parse-server/issues/8961)) ([cbefe77](https://github.com/parse-community/parse-server/commit/cbefe770a7260b54748a058b8a7389937dc35833))
* Incomplete user object in `verifyEmail` function if both username and email are changed ([#8889](https://github.com/parse-community/parse-server/issues/8889)) ([1eb95ae](https://github.com/parse-community/parse-server/commit/1eb95aeb41a96250e582d79a703f6adcb403c08b))
* Parse Server option `emailVerifyTokenReuseIfValid: true` generates new token on every email verification request ([#8885](https://github.com/parse-community/parse-server/issues/8885)) ([0023ce4](https://github.com/parse-community/parse-server/commit/0023ce448a5e9423337d0e1a25648bde1156bc95))
* Parse Server option `fileExtensions` default value rejects file extensions that are less than 3 or more than 4 characters long ([#8699](https://github.com/parse-community/parse-server/issues/8699)) ([2760381](https://github.com/parse-community/parse-server/commit/276038118377c2b22381bcd8d30337203822121b))
* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a))
* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c))
* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1))
* Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) ([#9024](https://github.com/parse-community/parse-server/issues/9024)) ([9f6e342](https://github.com/parse-community/parse-server/commit/9f6e3429d3b326cf4e2994733c618d08032fac6e))
* Server crashes when receiving an array of `Parse.Pointer` in the request body ([#8784](https://github.com/parse-community/parse-server/issues/8784)) ([66e3603](https://github.com/parse-community/parse-server/commit/66e36039d8af654cfa0284666c0ddd94975dcb52))
* Username is `undefined` in email verification link on email change ([#8887](https://github.com/parse-community/parse-server/issues/8887)) ([e315c13](https://github.com/parse-community/parse-server/commit/e315c137bf41bedfa8f0df537f2c3f6ab45b7e60))
### Features
* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29))
* Add `installationId` to arguments for `verifyUserEmails`, `preventLoginWithUnverifiedEmail` ([#8836](https://github.com/parse-community/parse-server/issues/8836)) ([a22dbe1](https://github.com/parse-community/parse-server/commit/a22dbe16d5ac0090608f6caaf0ebd134925b7fd4))
* Add `installationId`, `ip`, `resendRequest` to arguments passed to `verifyUserEmails` on verification email request ([#8873](https://github.com/parse-community/parse-server/issues/8873)) ([8adcbee](https://github.com/parse-community/parse-server/commit/8adcbee11283d3e95179ca2047e2615f52c18806))
* Add `Parse.User` as function parameter to Parse Server options `verifyUserEmails`, `preventLoginWithUnverifiedEmail` on login ([#8850](https://github.com/parse-community/parse-server/issues/8850)) ([972f630](https://github.com/parse-community/parse-server/commit/972f6300163b3cd7d95eeb95986e8322c95f821c))
* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620))
* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d))
* Add password validation via POST request for user with unverified email using master key and option `ignoreEmailVerification` ([#8895](https://github.com/parse-community/parse-server/issues/8895)) ([633a9d2](https://github.com/parse-community/parse-server/commit/633a9d25e4253e2125bc93c02ee8a37e0f5f7b83))
* Add support for MongoDB 7 ([#8761](https://github.com/parse-community/parse-server/issues/8761)) ([3de8494](https://github.com/parse-community/parse-server/commit/3de8494a221991dfd10a74e0a2dc89576265c9b7))
* Add support for MongoDB query comment ([#8928](https://github.com/parse-community/parse-server/issues/8928)) ([2170962](https://github.com/parse-community/parse-server/commit/2170962a50fa353ed85eda3f11dce7ee3647b087))
* Add support for Node 20, drop support for Node 14, 16 ([#8907](https://github.com/parse-community/parse-server/issues/8907)) ([ced4872](https://github.com/parse-community/parse-server/commit/ced487246ea0ef72a8aa014991f003209b34841e))
* Add support for Postgres 16 ([#8898](https://github.com/parse-community/parse-server/issues/8898)) ([99489b2](https://github.com/parse-community/parse-server/commit/99489b22e4f0982e6cb39992974b51aa8d3a31e4))
* Allow `Parse.Session.current` on expired session token instead of throwing error ([#8722](https://github.com/parse-community/parse-server/issues/8722)) ([f9dde4a](https://github.com/parse-community/parse-server/commit/f9dde4a9f8a90c63f71172c9bc515b0f6c6d2e4a))
* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d))
* Deprecation DEPPS5: Config option `allowClientClassCreation` defaults to `false` ([#8849](https://github.com/parse-community/parse-server/issues/8849)) ([29624e0](https://github.com/parse-community/parse-server/commit/29624e0fae17161cd412ae58d35a195cfa286cad))
* Deprecation DEPPS6: Authentication adapters disabled by default ([#8858](https://github.com/parse-community/parse-server/issues/8858)) ([0cf58eb](https://github.com/parse-community/parse-server/commit/0cf58eb8d60c8e5f485764e154f3214c49eee430))
* Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax ([#8855](https://github.com/parse-community/parse-server/issues/8855)) ([4e6a375](https://github.com/parse-community/parse-server/commit/4e6a375b5184ae0f7aa256a921eca4021c609435))
* Deprecation DEPPS8: Parse Server option `allowExpiredAuthDataToken` defaults to `false` ([#8860](https://github.com/parse-community/parse-server/issues/8860)) ([e29845f](https://github.com/parse-community/parse-server/commit/e29845f8dacac09ce3093d75c0d92330c24389e8))
* Deprecation DEPPS9: LiveQuery `fields` option is renamed to `keys` ([#8852](https://github.com/parse-community/parse-server/issues/8852)) ([38983e8](https://github.com/parse-community/parse-server/commit/38983e8e9b5cdbd006f311a2338103624137d013))
* Node process exits with error code 1 on uncaught exception to allow custom uncaught exception handling ([#8894](https://github.com/parse-community/parse-server/issues/8894)) ([70c280c](https://github.com/parse-community/parse-server/commit/70c280ca578ff28b5acf92f37fbe06d42a5b34ca))
* Switch GraphQL server from Yoga v2 to Apollo v4 ([#8959](https://github.com/parse-community/parse-server/issues/8959)) ([105ae7c](https://github.com/parse-community/parse-server/commit/105ae7c8a57d5a650b243174a80c26bf6db16e28))
* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740))
* Upgrade to Parse JS SDK 5 ([#9022](https://github.com/parse-community/parse-server/issues/9022)) ([ad4aa83](https://github.com/parse-community/parse-server/commit/ad4aa83983205a0e27639f6ee6a4a5963b67e4b8))
### Performance Improvements
* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522))
### BREAKING CHANGES
* The Parse Server option `allowClientClassCreation` defaults to `false`. ([29624e0](29624e0))
* A request using the master key will now be rejected as unauthorized if the IP from which the request originates is not set in the Parse Server option `masterKeyIps`, even if the request does not require the master key permission, for example for a public object in a public class class. ([a7b5b38](a7b5b38))
* Node process now exits with code 1 on uncaught exceptions, enabling custom handlers that were blocked by Parse Server's default behavior of re-throwing errors. This change may lead to automatic process restarts by the environment, unlike before. ([70c280c](70c280c))
* Authentication adapters are disabled by default; to use an authentication adapter it needs to be explicitly enabled in the Parse Server authentication adapter option `auth.<provider>.enabled: true` ([0cf58eb](0cf58eb))
* Parse Server option `allowExpiredAuthDataToken` defaults to `false`; a 3rd party authentication token will be validated every time the user tries to log in and the login will fail if the token has expired; the effect of this change may differ for different authentication adapters, depending on the token lifetime and the token refresh logic of the adapter ([e29845f](e29845f))
* LiveQuery `fields` option is renamed to `keys` ([38983e8](38983e8))
* Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'` ([4e6a375](4e6a375))
* Removes support for Node 14 and 16 ([ced4872](ced4872))
* Removes support for Postgres 11 and 12 ([99489b2](99489b2))
* The `Parse.User` passed as argument if `verifyUserEmails` is set to a function is renamed from `user` to `object` for consistency with invocations of `verifyUserEmails` on signup or login; the user object is not a plain JavaScript object anymore but an instance of `Parse.User` ([8adcbee](8adcbee))
* `Parse.Session.current()` no longer throws an error if the session token is expired, but instead returns the session token with its expiration date to allow checking its validity ([f9dde4a](f9dde4a))
* `Parse.Query` no longer supports the BSON type `code`; although this feature was never officially documented, its removal is announced as a breaking change to protect deployments where it might be in use. ([3de8494](3de8494))
# [6.4.0](https://github.com/parse-community/parse-server/compare/6.3.1...6.4.0) (2023-11-16)
### Bug Fixes
* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b))
* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49))
* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec))
* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64))
### Features
* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a))
* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298))
* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589))
### Performance Improvements
* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd))
## [6.3.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.3.1) (2023-10-20)
### Bug Fixes
* Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) ([#8781](https://github.com/parse-community/parse-server/issues/8781)) ([fd86278](https://github.com/parse-community/parse-server/commit/fd86278919556d3682e7e2c856dfccd5beffbfc0))
# [6.3.0](https://github.com/parse-community/parse-server/compare/6.2.2...6.3.0) (2023-09-16)
### Bug Fixes
* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804))
* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394))
* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4))
* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b))
* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e))
* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae))
### Features
* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029))
* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab))
* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d))
* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e))
* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e))
* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761))
### Reverts
* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff))
## [6.2.2](https://github.com/parse-community/parse-server/compare/6.2.1...6.2.2) (2023-09-04)
### Bug Fixes
* Parse Pointer allows to access internal Parse Server classes and circumvent `beforeFind` query trigger; fixes security vulnerability [GHSA-fcv6-fg5r-jm9q](https://github.com/parse-community/parse-server/security/advisories/GHSA-fcv6-fg5r-jm9q) ([be4c7e2](https://github.com/parse-community/parse-server/commit/be4c7e23c63a2fb690685665cebed0de26be05c5))
## [6.2.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.2.1) (2023-06-28)
### Bug Fixes
* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) ([#8674](https://github.com/parse-community/parse-server/issues/8674)) ([3dd99dd](https://github.com/parse-community/parse-server/commit/3dd99dd80e27e5e1d99b42844180546d90c7aa90))
# [6.2.0](https://github.com/parse-community/parse-server/compare/6.1.0...6.2.0) (2023-05-20)
### Features
* Add new Parse Server option `fileUpload.fileExtensions` to restrict file upload by file extension; this fixes a security vulnerability in which a phishing attack could be performed using an uploaded HTML file; by default the new option only allows file extensions matching the regex pattern `^[^hH][^tT][^mM][^lL]?$`, which excludes HTML files; if your app currently depends on uploading files with HTML file extensions then this may be a breaking change and you could allow HTML file upload by setting the option to `['.*']` ([#8538](https://github.com/parse-community/parse-server/issues/8538)) ([a318e7b](https://github.com/parse-community/parse-server/commit/a318e7bbafcf7a3425b0a1b3c2dd30f526b4b6f9))
# [6.1.0](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0) (2023-05-01)
### Bug Fixes
* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))
* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))
### Features
* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))
# [6.0.0](https://github.com/parse-community/parse-server/compare/5.4.0...6.0.0) (2023-01-31)
### Bug Fixes
* `ParseServer.verifyServerUrl` may fail if server response headers are missing; remove unnecessary logging ([#8391](https://github.com/parse-community/parse-server/issues/8391)) ([1c37a7c](https://github.com/parse-community/parse-server/commit/1c37a7cd0715949a70b220a629071c7dab7d5e7b))
* Cloud Code trigger `beforeSave` does not work with `Parse.Role` ([#8320](https://github.com/parse-community/parse-server/issues/8320)) ([f29d972](https://github.com/parse-community/parse-server/commit/f29d9720e9b37918fd885c97a31e34c42750e724))
* ES6 modules do not await the import of Cloud Code files ([#8368](https://github.com/parse-community/parse-server/issues/8368)) ([a7bd180](https://github.com/parse-community/parse-server/commit/a7bd180cddd784c8735622f22e012c342ad535fb))
* Nested objects are encoded incorrectly for MongoDB ([#8209](https://github.com/parse-community/parse-server/issues/8209)) ([1412666](https://github.com/parse-community/parse-server/commit/1412666f75829612de6fb9d7ccae35761c9b75cb))
* Parse Server option `masterKeyIps` does not include localhost by default for IPv6 ([#8322](https://github.com/parse-community/parse-server/issues/8322)) ([ab82635](https://github.com/parse-community/parse-server/commit/ab82635b0d4cf323a07ddee51fee587b43dce95c))
* Rate limiter may reject requests that contain a session token ([#8399](https://github.com/parse-community/parse-server/issues/8399)) ([c114dc8](https://github.com/parse-community/parse-server/commit/c114dc8831055d74187b9dfb4c9eeb558520237c))
* Remove Node 12 and Node 17 support ([#8279](https://github.com/parse-community/parse-server/issues/8279)) ([2546cc8](https://github.com/parse-community/parse-server/commit/2546cc8572bea6610cb9b3c7401d9afac0e3c1d6))
* Schema without class level permissions may cause error ([#8409](https://github.com/parse-community/parse-server/issues/8409)) ([aa2cd51](https://github.com/parse-community/parse-server/commit/aa2cd51b703388d925e4572e5c2b2d883c68e49c))
* The client IP address may be determined incorrectly in some cases; this fixes a security vulnerability in which the Parse Server option `masterKeyIps` may be circumvented, see [GHSA-vm5r-c87r-pf6x](https://github.com/parse-community/parse-server/security/advisories/GHSA-vm5r-c87r-pf6x) ([#8372](https://github.com/parse-community/parse-server/issues/8372)) ([892040d](https://github.com/parse-community/parse-server/commit/892040dc2f82a3e2abe2824e4b553521b6f894de))
* Throwing error in Cloud Code Triggers `afterLogin`, `afterLogout` crashes server ([#8280](https://github.com/parse-community/parse-server/issues/8280)) ([130d290](https://github.com/parse-community/parse-server/commit/130d29074e3f763460e5685d0b9059e5a333caff))
### Features
* Access the internal scope of Parse Server using the new `maintenanceKey`; the internal scope contains unofficial and undocumented fields (prefixed with underscore `_`) which are used internally by Parse Server; you may want to manipulate these fields for out-of-band changes such as data migration or correction tasks; changes within the internal scope of Parse Server may happen at any time without notice or changelog entry, it is therefore recommended to look at the source code of Parse Server to understand the effects of manipulating internal fields before using the key; it is discouraged to use the `maintenanceKey` for routine operations in a production environment; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) ([#8212](https://github.com/parse-community/parse-server/issues/8212)) ([f3bcc93](https://github.com/parse-community/parse-server/commit/f3bcc9365cd6f08b0a32c132e8e5ff6d1b650863))
* Adapt `verifyServerUrl` for new asynchronous Parse Server start-up states ([#8366](https://github.com/parse-community/parse-server/issues/8366)) ([ffa4974](https://github.com/parse-community/parse-server/commit/ffa4974158615fbff4a2692b9db41dcb50d3f77b))
* Add `ParseQuery.watch` to trigger LiveQuery only on update of specific fields ([#8028](https://github.com/parse-community/parse-server/issues/8028)) ([fc92faa](https://github.com/parse-community/parse-server/commit/fc92faac75107b3392eeddd916c4c5b45e3c5e0c))
* Add Node 19 support ([#8363](https://github.com/parse-community/parse-server/issues/8363)) ([a4990dc](https://github.com/parse-community/parse-server/commit/a4990dcd29abcb4442f3c424aff482a0a116160f))
* Add option to change the log level of the logs emitted by triggers ([#8328](https://github.com/parse-community/parse-server/issues/8328)) ([8f3b694](https://github.com/parse-community/parse-server/commit/8f3b694e39d4a966567e50dbea4d62e954fa5c06))
* Add request rate limiter based on IP address ([#8174](https://github.com/parse-community/parse-server/issues/8174)) ([6c79f6a](https://github.com/parse-community/parse-server/commit/6c79f6a69e25e47846e3b0685d6bdfd6b91086b1))
* Asynchronous initialization of Parse Server ([#8232](https://github.com/parse-community/parse-server/issues/8232)) ([99fcf45](https://github.com/parse-community/parse-server/commit/99fcf45e55c368de2345b0c4d780e70e0adf0e15))
* Improve authentication adapter interface to support multi-factor authentication (MFA), authentication challenges, and provide a more powerful interface for writing custom authentication adapters ([#8156](https://github.com/parse-community/parse-server/issues/8156)) ([5bbf9ca](https://github.com/parse-community/parse-server/commit/5bbf9cade9a527787fd1002072d4013ab5d8db2b))
* Reduce Docker image size by improving stages ([#8359](https://github.com/parse-community/parse-server/issues/8359)) ([40810b4](https://github.com/parse-community/parse-server/commit/40810b48ebde8b1f21d2448a3a4de0585b1b5e34))
* Remove deprecation `DEPPS1`: Native MongoDB syntax in aggregation pipeline ([#8362](https://github.com/parse-community/parse-server/issues/8362)) ([d0d30c4](https://github.com/parse-community/parse-server/commit/d0d30c4f1394f563724644a8fc81734be538a2c0))
* Remove deprecation `DEPPS2`: Config option `directAccess` defaults to true ([#8284](https://github.com/parse-community/parse-server/issues/8284)) ([f535ee6](https://github.com/parse-community/parse-server/commit/f535ee6ec2abba63f702127258ca49fa5b4e08c9))
* Remove deprecation `DEPPS3`: Config option `enforcePrivateUsers` defaults to `true` ([#8283](https://github.com/parse-community/parse-server/issues/8283)) ([ed499e3](https://github.com/parse-community/parse-server/commit/ed499e32a21bab9a874a9e5367dc71248ce836c4))
* Remove deprecation `DEPPS4`: Remove convenience method for http request `Parse.Cloud.httpRequest` ([#8287](https://github.com/parse-community/parse-server/issues/8287)) ([2d79c08](https://github.com/parse-community/parse-server/commit/2d79c0835b6a9acaf20d5c943d9b4619bb96831c))
* Remove support for MongoDB 4.0 ([#8292](https://github.com/parse-community/parse-server/issues/8292)) ([37245f6](https://github.com/parse-community/parse-server/commit/37245f62ce83516b6b95a54b850f0274ef680478))
* Restrict use of `masterKey` to localhost by default ([#8281](https://github.com/parse-community/parse-server/issues/8281)) ([6c16021](https://github.com/parse-community/parse-server/commit/6c16021a1f03a70a6d9e68cb64df362d07f3b693))
* Upgrade Node Package Manager lock file `package-lock.json` to version 2 ([#8285](https://github.com/parse-community/parse-server/issues/8285)) ([ee72467](https://github.com/parse-community/parse-server/commit/ee7246733d63e4bda20401f7b00262ff03299f20))
* Upgrade Redis 3 to 4 ([#8293](https://github.com/parse-community/parse-server/issues/8293)) ([7d622f0](https://github.com/parse-community/parse-server/commit/7d622f06a4347e0ad2cba9a4ec07d8d4fb0f67bc))
* Upgrade Redis 3 to 4 for LiveQuery ([#8333](https://github.com/parse-community/parse-server/issues/8333)) ([b2761fb](https://github.com/parse-community/parse-server/commit/b2761fb3786b519d9bbcf35be54309d2d35da1a9))
* Upgrade to Parse JavaScript SDK 4 ([#8332](https://github.com/parse-community/parse-server/issues/8332)) ([9092874](https://github.com/parse-community/parse-server/commit/9092874a9a482a24dfdce1dce56615702999d6b8))
* Write log entry when request with master key is rejected as outside of `masterKeyIps` ([#8350](https://github.com/parse-community/parse-server/issues/8350)) ([e22b73d](https://github.com/parse-community/parse-server/commit/e22b73d4b700c8ff745aa81726c6680082294b45))
### BREAKING CHANGES
* The Docker image does not contain the git dependency anymore; if you have been using git as a transitive dependency it now needs to be explicitly installed in your Docker file, for example with `RUN apk --no-cache add git` (#8359) ([40810b4](40810b4))
* Fields in the internal scope of Parse Server (prefixed with underscore `_`) are only returned using the new `maintenanceKey`; previously the `masterKey` allowed reading of internal fields; see [access scopes](https://github.com/parse-community/parse-server#access-scopes) for a comparison of the keys' access permissions (#8212) ([f3bcc93](f3bcc93))
* The method `ParseServer.verifyServerUrl` now returns a promise instead of a callback. ([ffa4974](ffa4974))
* The MongoDB aggregation pipeline requires native MongoDB syntax instead of the custom Parse Server syntax; for example pipeline stage names require a leading dollar sign like `$match` and the MongoDB document ID is referenced using `_id` instead of `objectId` (#8362) ([d0d30c4](d0d30c4))
* The mechanism to determine the client IP address has been rewritten; to correctly determine the IP address it is now required to set the Parse Server option `trustProxy` accordingly if Parse Server runs behind a proxy server, see the express framework's [trust proxy](https://expressjs.com/en/guide/behind-proxies.html) setting (#8372) ([892040d](892040d))
* The Node Package Manager lock file `package-lock.json` is upgraded to version 2; while it is backwards with version 1 for the npm installer, consider this if you run any non-npm analysis tools that use the lock file (#8285) ([ee72467](ee72467))
* This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232) ([99fcf45](99fcf45))
* Nested objects are now properly stored in the database using JSON serialization; previously, due to a bug only top-level objects were serialized, but nested objects were saved as raw JSON; for example, a nested `Date` object was saved as a JSON object like `{ "__type": "Date", "iso": "2020-01-01T00:00:00.000Z" }` instead of its serialized representation `2020-01-01T00:00:00.000Z` (#8209) ([1412666](1412666))
* The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283) ([ed499e3](ed499e3))
* This release restricts the use of `masterKey` to localhost by default; if you are using Parse Dashboard on a different server to connect to Parse Server you need to add the IP address of the server that hosts Parse Dashboard to this option (#8281) ([6c16021](6c16021))
* This release upgrades to Redis 4; if you are using the Redis cache adapter with Parse Server then this is a breaking change as the Redis client options have changed; see the [Redis migration guide](https://github.com/redis/node-redis/blob/redis%404.0.0/docs/v3-to-v4.md) for more details (#8293) ([7d622f0](7d622f0))
* This release removes support for MongoDB 4.0; the new minimum supported MongoDB version is 4.2. which also removes support for the deprecated MongoDB MMAPv1 storage engine ([37245f6](37245f6))
* Throwing an error in Cloud Code Triggers `afterLogin`, `afterLogout` returns a rejected promise; in previous releases it crashed the server if you did not handle the error on the Node.js process level; consider adapting your code if your app currently handles these errors on the Node.js process level with `process.on('unhandledRejection', ...)` ([130d290](130d290))
* Config option `directAccess` defaults to true; set this to `false` in environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`. ([f535ee6](f535ee6))
* The convenience method for HTTP requests `Parse.Cloud.httpRequest` is removed; use your preferred 3rd party library for making HTTP requests ([2d79c08](2d79c08))
* This release removes Node 12 and Node 17 support ([2546cc8](2546cc8))
# [5.4.0](https://github.com/parse-community/parse-server/compare/5.3.3...5.4.0) (2022-11-19)
### Bug Fixes
* graphQL query ignores condition `equalTo` with value `false` ([#8032](https://github.com/parse-community/parse-server/issues/8032)) ([7f5a15d](https://github.com/parse-community/parse-server/commit/7f5a15d5df0dfa3515e9f73709d6a49663545f9b))
* internal indices for classes `_Idempotency` and `_Role` are not protected in defined schema ([#8121](https://github.com/parse-community/parse-server/issues/8121)) ([c16f529](https://github.com/parse-community/parse-server/commit/c16f529f74f92154401bf662f634b3c5fa45e18e))
* liveQuery with `containedIn` not working when object field is an array ([#8128](https://github.com/parse-community/parse-server/issues/8128)) ([1d9605b](https://github.com/parse-community/parse-server/commit/1d9605bc93009263d3811df4d4249034ba6eb8c4))
* push notifications `badge` doesn't update with Installation beforeSave trigger ([#8162](https://github.com/parse-community/parse-server/issues/8162)) ([3c75c2b](https://github.com/parse-community/parse-server/commit/3c75c2ba4851fae96a8c19b11a3efde03816c9a1))
* query aggregation pipeline cannot handle value of type `Date` when `directAccess: true` ([#8167](https://github.com/parse-community/parse-server/issues/8167)) ([e424137](https://github.com/parse-community/parse-server/commit/e4241374061caef66538de15112fb6bbafb1f5bb))
* relation constraints in compound queries `Parse.Query.or`, `Parse.Query.and` not working ([#8203](https://github.com/parse-community/parse-server/issues/8203)) ([28f0d26](https://github.com/parse-community/parse-server/commit/28f0d2667787d2ac68726607b811d6f0ef62b9f1))
* security upgrade undici from 5.6.0 to 5.8.0 ([#8108](https://github.com/parse-community/parse-server/issues/8108)) ([4aa016b](https://github.com/parse-community/parse-server/commit/4aa016b7322467422b9fdf05d8e29b9ecf910da7))
* sorting by non-existing value throws `INVALID_SERVER_ERROR` on Postgres ([#8157](https://github.com/parse-community/parse-server/issues/8157)) ([3b775a1](https://github.com/parse-community/parse-server/commit/3b775a1fb8a1878714e3451191438963d688f1b0))
* updating object includes unchanged keys in client response for certain key types ([#8159](https://github.com/parse-community/parse-server/issues/8159)) ([37af1d7](https://github.com/parse-community/parse-server/commit/37af1d78fce5a15039ffe3af7b323c1f1e8582fc))
### Features
* add convenience access to Parse Server configuration in Cloud Code via `Parse.Server` ([#8244](https://github.com/parse-community/parse-server/issues/8244)) ([9f11115](https://github.com/parse-community/parse-server/commit/9f111158edf7fd57a65db0c4f9244b37e58cf293))
* add option to change the default value of the `Parse.Query.limit()` constraint ([#8152](https://github.com/parse-community/parse-server/issues/8152)) ([0388956](https://github.com/parse-community/parse-server/commit/038895680894984e569dff54bf5c7b31094f3891))
* add support for MongoDB 6 ([#8242](https://github.com/parse-community/parse-server/issues/8242)) ([aba0081](https://github.com/parse-community/parse-server/commit/aba0081ce1a166a93de57f3928c19a05562b5cc1))
* add support for Postgres 15 ([#8215](https://github.com/parse-community/parse-server/issues/8215)) ([2feb6c4](https://github.com/parse-community/parse-server/commit/2feb6c46080946c984daa351187fa07cd582355d))
* liveQuery support for unsorted distance queries ([#8221](https://github.com/parse-community/parse-server/issues/8221)) ([0f763da](https://github.com/parse-community/parse-server/commit/0f763da17d646b2fec2cd980d3857e46072a8a07))
## [5.3.3](https://github.com/parse-community/parse-server/compare/5.3.2...5.3.3) (2022-11-09)
### Bug Fixes
* Prototype pollution via Cloud Code Webhooks; fixes security vulnerability [GHSA-93vw-8fm5-p2jf](https://github.com/parse-community/parse-server/security/advisories/GHSA-93vw-8fm5-p2jf) ([#8305](https://github.com/parse-community/parse-server/issues/8305)) ([60c5a73](https://github.com/parse-community/parse-server/commit/60c5a73d257e0d536056b38bdafef8b7130524d8))
## [5.3.2](https://github.com/parse-community/parse-server/compare/5.3.1...5.3.2) (2022-11-09)
### Bug Fixes
* Parse Server option `requestKeywordDenylist` can be bypassed via Cloud Code Webhooks or Triggers; fixes security vulnerability [GHSA-xprv-wvh7-qqqx](https://github.com/parse-community/parse-server/security/advisories/GHSA-xprv-wvh7-qqqx) ([#8302](https://github.com/parse-community/parse-server/issues/8302)) ([6728da1](https://github.com/parse-community/parse-server/commit/6728da1e3591db1e27031d335d64d8f25546a06f))
## [5.3.1](https://github.com/parse-community/parse-server/compare/5.3.0...5.3.1) (2022-11-07)
### Bug Fixes
* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-prm5-8g2m-24gg](https://github.com/parse-community/parse-server/security/advisories/GHSA-prm5-8g2m-24gg) ([#8295](https://github.com/parse-community/parse-server/issues/8295)) ([50eed3c](https://github.com/parse-community/parse-server/commit/50eed3cffe80fadfb4bdac52b2783a18da2cfc4f))
# [5.3.0](https://github.com/parse-community/parse-server/compare/5.2.8...5.3.0) (2022-10-29)
### Bug Fixes
* afterSave trigger removes pointer in Parse object ([#7913](https://github.com/parse-community/parse-server/issues/7913)) ([47d796e](https://github.com/parse-community/parse-server/commit/47d796ea58f65e71612ce37149be692abc9ea97f))
* auto-release process may fail if optional back-merging task fails ([#8051](https://github.com/parse-community/parse-server/issues/8051)) ([cf925e7](https://github.com/parse-community/parse-server/commit/cf925e75e87a6989f41e2e2abb2aba4332b1e79f))
* custom database options are not passed to MongoDB GridFS ([#7911](https://github.com/parse-community/parse-server/issues/7911)) ([b1e5565](https://github.com/parse-community/parse-server/commit/b1e5565b22f2eff229571fe9a9500314bd30965b))
* depreciate allowClientClassCreation defaulting to true ([#7925](https://github.com/parse-community/parse-server/issues/7925)) ([38ed96a](https://github.com/parse-community/parse-server/commit/38ed96ace534d639db007aa7dd5387b2da8f03ae))
* errors in GraphQL do not show the original error but a general `Unexpected Error` ([#8045](https://github.com/parse-community/parse-server/issues/8045)) ([0d81887](https://github.com/parse-community/parse-server/commit/0d818879c217f9c56100a5f59868fa37e6d24b71))
* interrupted WebSocket connection not closed by LiveQuery server ([#8012](https://github.com/parse-community/parse-server/issues/8012)) ([2d5221e](https://github.com/parse-community/parse-server/commit/2d5221e48012fb7781c0406d543a922d313075ea))
* live query role cache does not clear when a user is added to a role ([#8026](https://github.com/parse-community/parse-server/issues/8026)) ([199dfc1](https://github.com/parse-community/parse-server/commit/199dfc17226d85a78ab85f24362cce740f4ada39))
* peer dependency mismatch for GraphQL dependencies ([#7934](https://github.com/parse-community/parse-server/issues/7934)) ([0a6faa8](https://github.com/parse-community/parse-server/commit/0a6faa81fa97f8620e7fd05e8c7bbdb4b7da9578))
* return correct response when revert is used in beforeSave ([#7839](https://github.com/parse-community/parse-server/issues/7839)) ([19900fc](https://github.com/parse-community/parse-server/commit/19900fcdf8c9f29a674fb62cf6e4b3341d796891))
* security upgrade @parse/fs-files-adapter from 1.2.1 to 1.2.2 ([#7948](https://github.com/parse-community/parse-server/issues/7948)) ([3a70fda](https://github.com/parse-community/parse-server/commit/3a70fda6798d4143f21046439b5eaf232a31bdb6))
* security upgrade moment from 2.29.1 to 2.29.2 ([#7931](https://github.com/parse-community/parse-server/issues/7931)) ([731c550](https://github.com/parse-community/parse-server/commit/731c5507144bbacff236097e7a2a03bfe54f6e10))
* security upgrade parse push adapter from 4.1.0 to 4.1.2 ([#7893](https://github.com/parse-community/parse-server/issues/7893)) ([93667b4](https://github.com/parse-community/parse-server/commit/93667b4e8402bf13b46c4d3ef12cec6532fd9da7))
* websocket connection of LiveQuery interrupts frequently ([#8048](https://github.com/parse-community/parse-server/issues/8048)) ([03caae1](https://github.com/parse-community/parse-server/commit/03caae1e611f28079cdddbbe433daaf69e3f595c))
### Features
* add MongoDB 5.1 compatibility ([#7682](https://github.com/parse-community/parse-server/issues/7682)) ([022a856](https://github.com/parse-community/parse-server/commit/022a85619d8a2c57a2f2938e245e4d8a47c15276))
* add MongoDB 5.2 support ([#7894](https://github.com/parse-community/parse-server/issues/7894)) ([5bfa716](https://github.com/parse-community/parse-server/commit/5bfa7160d9e35b237cbae1016ed86724aa99f8d7))
* add support for Node 17 and 18 ([#7896](https://github.com/parse-community/parse-server/issues/7896)) ([3e9f292](https://github.com/parse-community/parse-server/commit/3e9f292d840334244934cee9a34545ac86313549))
* align file trigger syntax with class trigger; use the new syntax `Parse.Cloud.beforeSave(Parse.File, (request) => {})`, the old syntax `Parse.Cloud.beforeSaveFile((request) => {})` has been deprecated ([#7966](https://github.com/parse-community/parse-server/issues/7966)) ([c6dcad8](https://github.com/parse-community/parse-server/commit/c6dcad8d167d44912dbd416d328519314c0809bd))
* replace GraphQL Apollo with GraphQL Yoga ([#7967](https://github.com/parse-community/parse-server/issues/7967)) ([1aa2204](https://github.com/parse-community/parse-server/commit/1aa2204aebfdbe273d54d6d56c6029f7c34aab14))
* selectively enable / disable default authentication adapters ([#7953](https://github.com/parse-community/parse-server/issues/7953)) ([c1e808f](https://github.com/parse-community/parse-server/commit/c1e808f9e807fc49508acbde0d8b3f2b901a1638))
* upgrade mongodb from 4.4.1 to 4.5.0 ([#7991](https://github.com/parse-community/parse-server/issues/7991)) ([e692b5d](https://github.com/parse-community/parse-server/commit/e692b5dd8214cdb0ce79bedd30d9aa3cf4de76a5))
### Performance Improvements
* reduce database operations when using the constant parameter in Cloud Function validation ([#7892](https://github.com/parse-community/parse-server/issues/7892)) ([041197f](https://github.com/parse-community/parse-server/commit/041197fb4ca1cd7cf18dc426ce38647267823668))
## [5.2.8](https://github.com/parse-community/parse-server/compare/5.2.7...5.2.8) (2022-10-14)
### Bug Fixes
* server crashes when receiving file download request with invalid byte range; this fixes a security vulnerability that allows an attacker to impact the availability of the server instance; the fix improves parsing of the range parameter to properly handle invalid range requests ([GHSA-h423-w6qv-2wj3](https://github.com/parse-community/parse-server/security/advisories/GHSA-h423-w6qv-2wj3)) ([#8235](https://github.com/parse-community/parse-server/issues/8235)) ([066f296](https://github.com/parse-community/parse-server/commit/066f29673ab4030b6b5b90c0c0326f7d3fe7612a))
## [5.2.7](https://github.com/parse-community/parse-server/compare/5.2.6...5.2.7) (2022-09-20)
### Bug Fixes
* authentication adapter app ID validation may be circumvented; this fixes a vulnerability that affects configurations which allow users to authenticate using the Parse Server authentication adapter for *Facebook* or *Spotify* and where the server-side authentication adapter configuration `appIds` is set as a string (e.g. `abc`) instead of an array of strings (e.g. `["abc"]`) ([GHSA-r657-33vp-gp22](https://github.com/parse-community/parse-server/security/advisories/GHSA-r657-33vp-gp22)) ([#8185](https://github.com/parse-community/parse-server/issues/8185)) ([ecf0814](https://github.com/parse-community/parse-server/commit/ecf0814499bde31ab6082b6e42854aa65ad2e03e))
## [5.2.6](https://github.com/parse-community/parse-server/compare/5.2.5...5.2.6) (2022-09-20)
### Bug Fixes
* session object properties can be updated by foreign user; this fixes a security vulnerability in which a foreign user can write to the session object of another user if the session object ID is known; the fix prevents writing to foreign session objects ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp)) ([#8182](https://github.com/parse-community/parse-server/issues/8182)) ([6d0b2f5](https://github.com/parse-community/parse-server/commit/6d0b2f534603301bb630d9c8e497af3bc7ff1d09))
## [5.2.5](https://github.com/parse-community/parse-server/compare/5.2.4...5.2.5) (2022-09-02)
### Bug Fixes
* brute force guessing of user sensitive data via search patterns; this fixes a security vulnerability in which internal and protected fields may be used as query constraints to guess the value of these fields and obtain sensitive data (GHSA-2m6g-crv8-p3c6) ([#8144](https://github.com/parse-community/parse-server/issues/8144)) ([e39d51b](https://github.com/parse-community/parse-server/commit/e39d51bd329cd978589983bd659db46e1d45aad4))
## [5.2.4](https://github.com/parse-community/parse-server/compare/5.2.3...5.2.4) (2022-06-30)
### Bug Fixes
* protected fields exposed via LiveQuery; this removes protected fields from the client response; this may be a breaking change if your app is currently expecting to receive these protected fields ([GHSA-crrq-vr9j-fxxh](https://github.com/parse-community/parse-server/security/advisories/GHSA-crrq-vr9j-fxxh)) (https://github.com/parse-community/parse-server/pull/8074) ([#8073](https://github.com/parse-community/parse-server/issues/8073)) ([309f64c](https://github.com/parse-community/parse-server/commit/309f64ced8700321df056fb3cc97f15007a00df1))
## [5.2.3](https://github.com/parse-community/parse-server/compare/5.2.2...5.2.3) (2022-06-17)
### Bug Fixes
* invalid file request not properly handled; this fixes a security vulnerability in which an invalid file request can crash the server ([GHSA-xw6g-jjvf-wwf9](https://github.com/parse-community/parse-server/security/advisories/GHSA-xw6g-jjvf-wwf9)) ([#8060](https://github.com/parse-community/parse-server/issues/8060)) ([5be375d](https://github.com/parse-community/parse-server/commit/5be375dec2fa35425c1003ae81c55995ac72af92))
## [5.2.2](https://github.com/parse-community/parse-server/compare/5.2.1...5.2.2) (2022-06-17)
### Bug Fixes
* certificate in Apple Game Center auth adapter not validated; this fixes a security vulnerability in which authentication could be bypassed using a fake certificate; if you are using the Apple Gamer Center auth adapter it is your responsibility to keep its root certificate up-to-date and we advice you read the security advisory ([GHSA-rh9j-f5f8-rvgc](https://github.com/parse-community/parse-server/security/advisories/GHSA-rh9j-f5f8-rvgc)) ([ba2b0a9](https://github.com/parse-community/parse-server/commit/ba2b0a9cb9a568817a114b132a4c2e0911d76df1))
## [5.2.1](https://github.com/parse-community/parse-server/compare/5.2.0...5.2.1) (2022-05-01)
+20 -20
View File
@@ -1,8 +1,7 @@
'use strict';
const CiVersionCheck = require('./CiVersionCheck');
const mongoVersionList = require('mongodb-version-list');
const allNodeVersions = require('all-node-versions');
const { exec } = require('child_process');
async function check() {
// Run checks
@@ -14,14 +13,16 @@ 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) {
let latestStableVersions = await new Promise((resolve, reject) => {
exec('m ls', (error, stdout) => {
if (error) {
reject(error);
return;
}
resolve(versions);
resolve(stdout.trim());
});
});
latestStableVersions = latestStableVersions.split('\n').map(version => version.trim());
await new CiVersionCheck({
packageName: 'MongoDB',
@@ -29,15 +30,14 @@ async function checkMongoDbVersions() {
yamlFilePath: './.github/workflows/ci.yml',
ciEnvironmentsKeyPath: 'jobs.check-mongo.strategy.matrix.include',
ciVersionKey: 'MONGODB_VERSION',
releasedVersions,
latestComponent: CiVersionCheck.versionComponents.path,
releasedVersions: latestStableVersions,
latestComponent: CiVersionCheck.versionComponents.patch,
ignoreReleasedVersions: [
'<4.0.0', // Versions reached their MongoDB end-of-life support date
'~4.1.0', // Development release according to MongoDB support
'~4.3.0', // Development release according to MongoDB support
'~4.7.0', // Development release according to MongoDB support
'4.0.26', // Temporarily disabled because not yet available for download via mongodb-runner
'<4.2.0', // These versions have reached their end-of-life support date
'>=4.3.0 <5.0.0', // Unsupported rapid release versions
'>=5.1.0 <6.0.0', // Unsupported rapid release versions
'>=6.1.0 <7.0.0', // Unsupported rapid release versions
'>=7.1.0 <8.0.0', // Unsupported rapid release versions
],
}).check();
}
@@ -46,8 +46,9 @@ async function checkMongoDbVersions() {
* Check the Nodejs versions used in test environments.
*/
async function checkNodeVersions() {
const allVersions = await allNodeVersions();
const releasedVersions = allVersions.versions;
const allVersions = (await import('all-node-versions')).default;
const { versions } = await allVersions();
const nodeVersions = versions.map(version => version.node);
await new CiVersionCheck({
packageName: 'Node.js',
@@ -55,13 +56,12 @@ async function checkNodeVersions() {
yamlFilePath: './.github/workflows/ci.yml',
ciEnvironmentsKeyPath: 'jobs.check-mongo.strategy.matrix.include',
ciVersionKey: 'NODE_VERSION',
releasedVersions,
releasedVersions: nodeVersions,
latestComponent: CiVersionCheck.versionComponents.minor,
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
'>=15.0.0 <16.0.0', // These versions have reached their end-of-life support date
'>=19.0.0', // These versions are not officially supported yet
'<18.0.0', // These versions have reached their end-of-life support date
'>=19.0.0 <20.0.0', // These versions have reached their end-of-life support date
'>=21.0.0', // These versions are not officially supported yet
],
}).check();
}
+26
View File
@@ -0,0 +1,26 @@
const fs = require('fs').promises;
const { exec } = require('child_process');
const core = require('@actions/core');
const util = require('util');
(async () => {
const [currentDefinitions, currentDocs] = await Promise.all([
fs.readFile('./src/Options/Definitions.js', 'utf8'),
fs.readFile('./src/Options/docs.js', 'utf8'),
]);
const execute = util.promisify(exec);
await execute('npm run definitions');
const [newDefinitions, newDocs] = await Promise.all([
fs.readFile('./src/Options/Definitions.js', 'utf8'),
fs.readFile('./src/Options/docs.js', 'utf8'),
]);
if (currentDefinitions !== newDefinitions || currentDocs !== newDocs) {
console.error(
'\x1b[31m%s\x1b[0m',
'Definitions files cannot be updated manually. Please update src/Options/index.js then run `npm run definitions` to generate definitions.'
);
core.error('Definitions files cannot be updated manually. Please update src/Options/index.js then run `npm run definitions` to generate definitions.');
process.exit(1);
} else {
process.exit(0);
}
})();
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# Read package exclusion list from arguments
exclusionList=("$@")
# Convert exclusion list to grep pattern
exclusionPattern=$(printf "|%s" "${exclusionList[@]}")
exclusionPattern=${exclusionPattern:1}
# Get list of all dev dependencies
devDeps=$(jq -r '.devDependencies | keys | .[]' package.json)
# Filter out exclusion list
depsToUninstall=$(echo "$devDeps" | grep -Ev "$exclusionPattern")
# If there are dependencies to uninstall then uninstall them
if [ -n "$depsToUninstall" ]; then
echo "Uninstalling dev dependencies: $depsToUninstall"
npm uninstall $depsToUninstall
else
echo "No dev dependencies to uninstall"
fi
+22 -5
View File
@@ -1,10 +1,16 @@
{
"plugins": ["node_modules/jsdoc-babel", "plugins/markdown"],
"babel": {
"plugins": ["@babel/plugin-transform-flow-strip-types"]
"plugins": ["@babel/plugin-transform-flow-strip-types"]
},
"source": {
"include": ["./README.md", "./src/cloud-code", "./src/Options/docs.js", "./src/ParseServer.js", "./src/Adapters"],
"include": [
"README.md",
"./src/cloud-code",
"./src/Options/docs.js",
"./src/ParseServer.js",
"./src/Adapters"
],
"excludePattern": "(^|\\/|\\\\)_"
},
"templates": {
@@ -17,7 +23,18 @@
"monospaceLinks": false
},
"opts": {
"template": "node_modules/@parse/minami",
"recurse": true
"encoding": "utf8",
"readme": "./README.md",
"recurse": true,
"template": "./node_modules/clean-jsdoc-theme",
"theme_opts": {
"default_theme": "dark",
"title": "<img src='https://raw.githubusercontent.com/parse-community/parse-server/alpha/.github/parse-server-logo.png' class='logo'/>",
"create_style": "header, .sidebar-section-title, .sidebar-title { color: #139cee !important } .logo { margin-left : 40px; margin-right: 40px }"
}
},
"markdown": {
"hardwrap": false,
"idInHeadings": true
}
}
}
+29935 -9270
View File
File diff suppressed because it is too large Load Diff
+77 -73
View File
@@ -1,6 +1,6 @@
{
"name": "parse-server",
"version": "5.3.0-beta.1",
"version": "7.2.0",
"description": "An express module providing a Parse-compatible API server",
"main": "lib/index.js",
"repository": {
@@ -13,120 +13,124 @@
"public_html/",
"views/",
"LICENSE",
"PATENTS",
"NOTICE",
"postinstall.js",
"README.md"
],
"license": "BSD-3-Clause",
"license": "Apache-2.0",
"dependencies": {
"@graphql-yoga/node": "2.6.0",
"@graphql-tools/utils": "8.6.12",
"@graphql-tools/merge": "8.2.13",
"@graphql-tools/schema": "8.3.13",
"@parse/fs-files-adapter": "1.2.2",
"@parse/push-adapter": "4.1.2",
"@apollo/server": "4.10.1",
"@babel/eslint-parser": "7.21.8",
"@graphql-tools/merge": "9.0.3",
"@graphql-tools/schema": "10.0.3",
"@graphql-tools/utils": "8.12.0",
"@parse/fs-files-adapter": "3.0.0",
"@parse/push-adapter": "6.4.1",
"bcryptjs": "2.4.3",
"body-parser": "1.20.0",
"commander": "5.1.0",
"body-parser": "1.20.2",
"commander": "12.0.0",
"cors": "2.8.5",
"deepcopy": "2.1.0",
"express": "4.18.1",
"follow-redirects": "1.15.0",
"graphql": "16.5.0",
"graphql-list-fields": "2.0.2",
"express": "4.19.2",
"express-rate-limit": "6.11.2",
"follow-redirects": "1.15.6",
"graphql": "16.8.1",
"graphql-list-fields": "2.0.4",
"graphql-relay": "0.10.1",
"graphql-tag": "2.12.6",
"graphql-relay": "0.10.0",
"graphql-upload": "15.0.2",
"intersect": "1.0.1",
"jsonwebtoken": "8.5.1",
"jwks-rsa": "2.1.3",
"ldapjs": "2.3.2",
"jsonwebtoken": "9.0.2",
"jwks-rsa": "3.1.0",
"ldapjs": "3.0.7",
"lodash": "4.17.21",
"lru-cache": "7.10.1",
"lru-cache": "10.2.2",
"mime": "3.0.0",
"mongodb": "4.6.0",
"mongodb": "5.9.0",
"mustache": "4.2.0",
"parse": "3.4.2",
"pg-monitor": "1.4.1",
"pg-promise": "10.11.1",
"otpauth": "9.2.2",
"parse": "5.3.0",
"path-to-regexp": "6.2.1",
"pg-monitor": "2.0.0",
"pg-promise": "11.7.8",
"pluralize": "8.0.0",
"redis": "3.1.2",
"semver": "7.3.7",
"rate-limit-redis": "4.2.0",
"redis": "4.6.13",
"semver": "7.6.0",
"subscriptions-transport-ws": "0.11.0",
"tv4": "1.3.0",
"uuid": "8.3.2",
"winston": "3.7.2",
"winston-daily-rotate-file": "4.6.1",
"ws": "8.6.0"
"uuid": "9.0.1",
"winston": "3.12.0",
"winston-daily-rotate-file": "5.0.0",
"ws": "8.17.1"
},
"devDependencies": {
"graphql-tag": "2.12.6",
"@actions/core": "1.2.6",
"@apollo/client": "3.6.1",
"@babel/cli": "7.10.0",
"@babel/core": "7.10.0",
"@actions/core": "1.10.1",
"@apollo/client": "3.9.11",
"@babel/cli": "7.23.9",
"@babel/core": "7.24.7",
"@babel/plugin-proposal-object-rest-spread": "7.10.0",
"@babel/plugin-transform-flow-strip-types": "7.9.0",
"@babel/preset-env": "7.10.0",
"@parse/minami": "1.0.0",
"@saithodev/semantic-release-backmerge": "2.1.2",
"@semantic-release/changelog": "5.0.1",
"@semantic-release/commit-analyzer": "8.0.1",
"@semantic-release/git": "9.0.0",
"@semantic-release/github": "7.2.3",
"@semantic-release/npm": "7.1.3",
"@semantic-release/release-notes-generator": "9.0.3",
"all-node-versions": "8.0.0",
"apollo-upload-client": "16.0.0",
"apollo-utilities": "1.3.4",
"babel-eslint": "10.1.0",
"bcrypt-nodejs": "0.0.3",
"@babel/plugin-transform-flow-strip-types": "7.23.3",
"@babel/preset-env": "7.24.0",
"@saithodev/semantic-release-backmerge": "4.0.1",
"@semantic-release/changelog": "6.0.3",
"@semantic-release/commit-analyzer": "13.0.0",
"@semantic-release/git": "10.0.1",
"@semantic-release/github": "10.1.0",
"@semantic-release/npm": "12.0.1",
"@semantic-release/release-notes-generator": "14.0.1",
"all-node-versions": "12.1.0",
"apollo-upload-client": "17.0.0",
"clean-jsdoc-theme": "4.2.18",
"cross-env": "7.0.2",
"deep-diff": "1.0.2",
"eslint": "6.8.0",
"eslint-plugin-flowtype": "5.1.3",
"eslint": "8.26.0",
"eslint-plugin-flowtype": "8.0.3",
"flow-bin": "0.119.1",
"form-data": "3.0.0",
"husky": "4.2.5",
"form-data": "4.0.0",
"graphql-tag": "2.12.6",
"husky": "9.0.11",
"jasmine": "3.5.0",
"jasmine-spec-reporter": "7.0.0",
"jsdoc": "3.6.3",
"jsdoc": "4.0.2",
"jsdoc-babel": "0.5.0",
"lint-staged": "10.2.3",
"madge": "5.0.1",
"m": "1.9.0",
"madge": "6.1.0",
"mock-files-adapter": "file:spec/dependencies/mock-files-adapter",
"mock-mail-adapter": "file:spec/dependencies/mock-mail-adapter",
"mongodb-runner": "4.8.1",
"mongodb-version-list": "1.0.0",
"node-fetch": "3.2.4",
"mongodb-runner": "5.5.4",
"node-abort-controller": "3.1.1",
"node-fetch": "3.2.10",
"nyc": "15.1.0",
"prettier": "2.0.5",
"semantic-release": "17.4.6",
"semantic-release": "24.0.0",
"yaml": "1.10.0"
},
"scripts": {
"ci:check": "node ./ci/ciCheck.js",
"ci:checkNodeEngine": "node ./ci/nodeEngineCheck.js",
"ci:definitionsCheck": "node ./ci/definitionsCheck.js",
"definitions": "node ./resources/buildConfigDefinitions.js && prettier --write 'src/Options/*.js'",
"docs": "jsdoc -c ./jsdoc-conf.json",
"lint": "flow && eslint --cache ./",
"lint-fix": "eslint --fix --cache ./",
"build": "babel src/ -d lib/ --copy-files",
"watch": "babel --watch src/ -d lib/ --copy-files",
"test:mongodb:runnerstart": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start",
"test:mongodb:testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 jasmine",
"test:mongodb:runnerstart": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017",
"test:mongodb:testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 jasmine",
"test:mongodb": "npm run test:mongodb:runnerstart --dbversion=$npm_config_dbversion && npm run test:mongodb:testonly --dbversion=$npm_config_dbversion",
"test:mongodb:4.0.28": "npm run test:mongodb --dbversion=4.0.28",
"test:mongodb:4.2.19": "npm run test:mongodb --dbversion=4.2.19",
"test:mongodb:4.4.13": "npm run test:mongodb --dbversion=4.4.13",
"test:mongodb:5.0.6": "npm run test:mongodb --dbversion=5.0.6",
"test:mongodb:5.1.1": "npm run test:mongodb --dbversion=5.1.1",
"test:mongodb:5.2.1": "npm run test:mongodb --dbversion=5.2.1",
"posttest:mongodb": "mongodb-runner stop",
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner start",
"testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 jasmine",
"test:mongodb:5.3.2": "npm run test:mongodb --dbversion=5.3.2",
"test:mongodb:6.0.2": "npm run test:mongodb --dbversion=6.0.2",
"test:mongodb:7.0.1": "npm run test:mongodb --dbversion=7.0.1",
"test:postgres:testonly": "cross-env PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly",
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017",
"testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 jasmine",
"test": "npm run testonly",
"posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} mongodb-runner stop",
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.2.1} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=wiredTiger} TESTING=1 nyc jasmine",
"posttest": "cross-env mongodb-runner stop --all",
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 nyc jasmine",
"start": "node ./bin/parse-server",
"prettier": "prettier --write {src,spec}/{**/*,*}.js",
"prepare": "npm run build",
@@ -134,13 +138,13 @@
"madge:circular": "node_modules/.bin/madge ./src --circular"
},
"engines": {
"node": ">=12.22.10 <19"
"node": ">=18.0.0 <21"
},
"bin": {
"parse-server": "bin/parse-server"
},
"optionalDependencies": {
"@node-rs/bcrypt": "1.1.0"
"@node-rs/bcrypt": "1.10.4"
},
"collective": {
"type": "opencollective",
+1 -1
View File
@@ -1,6 +1,6 @@
const pkg = require('./package.json');
const version = parseFloat(process.version.substr(1));
const version = parseFloat(process.version.substring(1));
const minimum = parseFloat(pkg.engines.node.match(/\d+/g).join('.'));
module.exports = function () {
+21 -9
View File
@@ -1,10 +1,17 @@
#!/bin/sh -e
set -x
# GITHUB_ACTIONS=true SOURCE_TAG=test ./release_docs.sh
if [ "${GITHUB_ACTIONS}" = "" ];
then
echo "Cannot release docs without GITHUB_ACTIONS set"
exit 0;
fi
if [ "${SOURCE_TAG}" = "" ];
then
echo "Cannot release docs without SOURCE_TAG set"
exit 0;
fi
REPO="https://github.com/parse-community/parse-server"
rm -rf docs
@@ -13,17 +20,22 @@ cd docs
git pull origin gh-pages
cd ..
DEST="master"
RELEASE="release"
VERSION="${SOURCE_TAG}"
if [ "${SOURCE_TAG}" != "" ];
then
DEST="${SOURCE_TAG}"
# change the default page to the latest
echo "<meta http-equiv='refresh' content='0; url=/parse-server/api/${DEST}'>" > "docs/api/index.html"
fi
# change the default page to the latest
echo "<meta http-equiv='refresh' content='0; url=/parse-server/api/${VERSION}'>" > "docs/api/index.html"
npm run definitions
npm run docs
mkdir -p "docs/api/${DEST}"
cp -R out/* "docs/api/${DEST}"
mkdir -p "docs/api/${RELEASE}"
cp -R out/* "docs/api/${RELEASE}"
mkdir -p "docs/api/${VERSION}"
cp -R out/* "docs/api/${VERSION}"
# Copy other resources
RESOURCE_DIR=".github"
mkdir -p "docs/${RESOURCE_DIR}"
cp "./.github/parse-server-logo.png" "docs/${RESOURCE_DIR}/"
+165 -110
View File
@@ -24,31 +24,34 @@ const nestedOptionTypes = [
'PasswordPolicyOptions',
'SecurityOptions',
'SchemaOptions',
'LogLevels',
];
/** The prefix of environment variables for nested options. */
const nestedOptionEnvPrefix = {
'AccountLockoutOptions': 'PARSE_SERVER_ACCOUNT_LOCKOUT_',
'CustomPagesOptions': 'PARSE_SERVER_CUSTOM_PAGES_',
'DatabaseOptions': 'PARSE_SERVER_DATABASE_',
'FileUploadOptions': 'PARSE_SERVER_FILE_UPLOAD_',
'IdempotencyOptions': 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_',
'LiveQueryOptions': 'PARSE_SERVER_LIVEQUERY_',
'LiveQueryServerOptions': 'PARSE_LIVE_QUERY_SERVER_',
'PagesCustomUrlsOptions': 'PARSE_SERVER_PAGES_CUSTOM_URL_',
'PagesOptions': 'PARSE_SERVER_PAGES_',
'PagesRoute': 'PARSE_SERVER_PAGES_ROUTE_',
'ParseServerOptions': 'PARSE_SERVER_',
'PasswordPolicyOptions': 'PARSE_SERVER_PASSWORD_POLICY_',
'SecurityOptions': 'PARSE_SERVER_SECURITY_',
'SchemaOptions': 'PARSE_SERVER_SCHEMA_',
AccountLockoutOptions: 'PARSE_SERVER_ACCOUNT_LOCKOUT_',
CustomPagesOptions: 'PARSE_SERVER_CUSTOM_PAGES_',
DatabaseOptions: 'PARSE_SERVER_DATABASE_',
FileUploadOptions: 'PARSE_SERVER_FILE_UPLOAD_',
IdempotencyOptions: 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_',
LiveQueryOptions: 'PARSE_SERVER_LIVEQUERY_',
LiveQueryServerOptions: 'PARSE_LIVE_QUERY_SERVER_',
PagesCustomUrlsOptions: 'PARSE_SERVER_PAGES_CUSTOM_URL_',
PagesOptions: 'PARSE_SERVER_PAGES_',
PagesRoute: 'PARSE_SERVER_PAGES_ROUTE_',
ParseServerOptions: 'PARSE_SERVER_',
PasswordPolicyOptions: 'PARSE_SERVER_PASSWORD_POLICY_',
SecurityOptions: 'PARSE_SERVER_SECURITY_',
SchemaOptions: 'PARSE_SERVER_SCHEMA_',
LogLevels: 'PARSE_SERVER_LOG_LEVELS_',
RateLimitOptions: 'PARSE_SERVER_RATE_LIMIT_',
};
function last(array) {
return array[array.length - 1];
}
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
function toENV(key) {
let str = '';
let previousIsUpper = false;
@@ -68,13 +71,15 @@ function toENV(key) {
}
function getCommentValue(comment) {
if (!comment) { return }
if (!comment) {
return;
}
return comment.value.trim();
}
function getENVPrefix(iface) {
if (nestedOptionEnvPrefix[iface.id.name]) {
return nestedOptionEnvPrefix[iface.id.name]
return nestedOptionEnvPrefix[iface.id.name];
}
}
@@ -86,11 +91,11 @@ function processProperty(property, iface) {
if (!firstComment) {
return;
}
const lines = firstComment.split('\n').map((line) => line.trim());
const lines = firstComment.split('\n').map(line => line.trim());
let help = '';
let envLine;
let defaultLine;
lines.forEach((line) => {
lines.forEach(line => {
if (line.indexOf(':ENV:') === 0) {
envLine = line;
} else if (line.indexOf(':DEFAULT:') === 0) {
@@ -103,11 +108,13 @@ function processProperty(property, iface) {
if (envLine) {
env = envLine.split(' ')[1];
} else {
env = (prefix + toENV(name));
env = prefix + toENV(name);
}
let defaultValue;
if (defaultLine) {
defaultValue = defaultLine.split(' ')[1];
const defaultArray = defaultLine.split(' ');
defaultArray.shift();
defaultValue = defaultArray.join(' ');
}
let type = property.value.type;
let isRequired = true;
@@ -123,21 +130,20 @@ function processProperty(property, iface) {
defaultValue,
types: property.value.types,
typeAnnotation: property.value.typeAnnotation,
required: isRequired
required: isRequired,
};
}
function doInterface(iface) {
return iface.body.properties
.sort((a, b) => a.key.name.localeCompare(b.key.name))
.map((prop) => processProperty(prop, iface))
.filter((e) => e !== undefined);
.map(prop => processProperty(prop, iface))
.filter(e => e !== undefined);
}
function mapperFor(elt, t) {
const p = t.identifier('parsers');
const wrap = (identifier) => t.memberExpression(p, identifier);
const wrap = identifier => t.memberExpression(p, identifier);
if (t.isNumberTypeAnnotation(elt)) {
return t.callExpression(wrap(t.identifier('numberParser')), [t.stringLiteral(elt.name)]);
@@ -155,6 +161,9 @@ function mapperFor(elt, t) {
if (type == 'NumberOrBoolean') {
return wrap(t.identifier('numberOrBooleanParser'));
}
if (type === 'StringOrStringArray') {
return wrap(t.identifier('arrayParser'));
}
return wrap(t.identifier('objectParser'));
}
}
@@ -171,27 +180,29 @@ function parseDefaultValue(elt, value, t) {
literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value));
} else if (t.isArrayTypeAnnotation(elt)) {
const array = parsers.objectParser(value);
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');
}
}));
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');
}
})
);
} else if (t.isAnyTypeAnnotation(elt)) {
literalValue = t.arrayExpression([]);
} else if (t.isBooleanTypeAnnotation(elt)) {
@@ -204,15 +215,16 @@ function parseDefaultValue(elt, value, t) {
if (nestedOptionTypes.includes(type)) {
const object = parsers.objectParser(value);
const props = Object.keys(object).map((key) => {
const props = Object.keys(object).map(key => {
return t.objectProperty(key, object[value]);
});
literalValue = t.objectExpression(props);
}
if (type == 'ProtectedFields') {
const prop = t.objectProperty(
t.stringLiteral('_User'), t.objectPattern([
t.objectProperty(t.stringLiteral('*'), t.arrayExpression([t.stringLiteral('email')]))
t.stringLiteral('_User'),
t.objectPattern([
t.objectProperty(t.stringLiteral('*'), t.arrayExpression([t.stringLiteral('email')])),
])
);
literalValue = t.objectExpression([prop]);
@@ -223,62 +235,98 @@ function parseDefaultValue(elt, value, t) {
function inject(t, list) {
let comments = '';
const results = list.map((elt) => {
if (!elt.name) {
return;
}
const props = ['env', 'help'].map((key) => {
if (elt[key]) {
return t.objectProperty(t.stringLiteral(key), t.stringLiteral(elt[key]));
const results = list
.map(elt => {
if (!elt.name) {
return;
}
}).filter((e) => e !== undefined);
if (elt.required) {
props.push(t.objectProperty(t.stringLiteral('required'), t.booleanLiteral(true)))
}
const action = mapperFor(elt, t);
if (action) {
props.push(t.objectProperty(t.stringLiteral('action'), action))
}
if (elt.defaultValue) {
const parsedValue = parseDefaultValue(elt, elt.defaultValue, t);
if (parsedValue) {
props.push(t.objectProperty(t.stringLiteral('default'), parsedValue));
} else {
throw new Error(`Unable to parse value for ${elt.name} `);
const props = ['env', 'help']
.map(key => {
if (elt[key]) {
return t.objectProperty(t.stringLiteral(key), t.stringLiteral(elt[key]));
}
})
.filter(e => e !== undefined);
if (elt.required) {
props.push(t.objectProperty(t.stringLiteral('required'), t.booleanLiteral(true)));
}
}
let type = elt.type.replace('TypeAnnotation', '');
if (type === 'Generic') {
type = elt.typeAnnotation.id.name;
}
if (type === 'Array') {
type = elt.typeAnnotation.elementType.id
? `${elt.typeAnnotation.elementType.id.name}[]`
: `${elt.typeAnnotation.elementType.type.replace('TypeAnnotation', '')}[]`;
}
if (type === 'NumberOrBoolean') {
type = 'Number|Boolean';
}
if (type === 'NumberOrString') {
type = 'Number|String';
}
if (type === 'Adapter') {
const adapterType = elt.typeAnnotation.typeParameters.params[0].id.name;
type = `Adapter<${adapterType}>`;
}
comments += ` * @property {${type}} ${elt.name} ${elt.help}\n`;
const obj = t.objectExpression(props);
return t.objectProperty(t.stringLiteral(elt.name), obj);
}).filter((elt) => {
return elt != undefined;
});
const action = mapperFor(elt, t);
if (action) {
props.push(t.objectProperty(t.stringLiteral('action'), action));
}
if (t.isGenericTypeAnnotation(elt)) {
if (elt.typeAnnotation.id.name in nestedOptionEnvPrefix) {
props.push(
t.objectProperty(t.stringLiteral('type'), t.stringLiteral(elt.typeAnnotation.id.name))
);
}
} else if (t.isArrayTypeAnnotation(elt)) {
const elementType = elt.typeAnnotation.elementType;
if (t.isGenericTypeAnnotation(elementType)) {
if (elementType.id.name in nestedOptionEnvPrefix) {
props.push(
t.objectProperty(t.stringLiteral('type'), t.stringLiteral(elementType.id.name + '[]'))
);
}
}
}
if (elt.defaultValue) {
let parsedValue = parseDefaultValue(elt, elt.defaultValue, t);
if (!parsedValue) {
for (const type of elt.typeAnnotation.types) {
elt.type = type.type;
parsedValue = parseDefaultValue(elt, elt.defaultValue, t);
if (parsedValue) {
break;
}
}
}
if (parsedValue) {
props.push(t.objectProperty(t.stringLiteral('default'), parsedValue));
} else {
throw new Error(`Unable to parse value for ${elt.name} `);
}
}
let type = elt.type.replace('TypeAnnotation', '');
if (type === 'Generic') {
type = elt.typeAnnotation.id.name;
}
if (type === 'Array') {
type = elt.typeAnnotation.elementType.id
? `${elt.typeAnnotation.elementType.id.name}[]`
: `${elt.typeAnnotation.elementType.type.replace('TypeAnnotation', '')}[]`;
}
if (type === 'NumberOrBoolean') {
type = 'Number|Boolean';
}
if (type === 'NumberOrString') {
type = 'Number|String';
}
if (type === 'Adapter') {
const adapterType = elt.typeAnnotation.typeParameters.params[0].id.name;
type = `Adapter<${adapterType}>`;
}
if (type === 'StringOrStringArray') {
type = 'String|String[]';
}
comments += ` * @property {${type}} ${elt.name} ${elt.help}\n`;
const obj = t.objectExpression(props);
return t.objectProperty(t.stringLiteral(elt.name), obj);
})
.filter(elt => {
return elt != undefined;
});
return { results, comments };
}
const makeRequire = function (variableName, module, t) {
const decl = t.variableDeclarator(t.identifier(variableName), t.callExpression(t.identifier('require'), [t.stringLiteral(module)]));
return t.variableDeclaration('var', [decl])
}
const decl = t.variableDeclarator(
t.identifier(variableName),
t.callExpression(t.identifier('require'), [t.stringLiteral(module)])
);
return t.variableDeclaration('var', [decl]);
};
let docs = ``;
const plugin = function (babel) {
const t = babel.types;
@@ -294,27 +342,34 @@ const plugin = function (babel) {
},
ExportDeclaration: function (path) {
// Export declaration on an interface
if (path.node && path.node.declaration && path.node.declaration.type == 'InterfaceDeclaration') {
if (
path.node &&
path.node.declaration &&
path.node.declaration.type == 'InterfaceDeclaration'
) {
const { results, comments } = inject(t, doInterface(path.node.declaration));
const id = path.node.declaration.id.name;
const exports = t.memberExpression(moduleExports, t.identifier(id));
docs += `/**\n * @interface ${id}\n${comments} */\n\n`;
path.replaceWith(
t.assignmentExpression('=', exports, t.objectExpression(results))
)
path.replaceWith(t.assignmentExpression('=', exports, t.objectExpression(results)));
}
}
}
}
},
},
};
};
const auxiliaryCommentBefore = `
**** GENERATED CODE ****
This code has been generated by resources/buildConfigDefinitions.js
Do not edit manually, but update Options/index.js
`
`;
const babel = require("@babel/core");
const res = babel.transformFileSync('./src/Options/index.js', { plugins: [plugin, '@babel/transform-flow-strip-types'], babelrc: false, auxiliaryCommentBefore, sourceMaps: false });
const babel = require('@babel/core');
const res = babel.transformFileSync('./src/Options/index.js', {
plugins: [plugin, '@babel/transform-flow-strip-types'],
babelrc: false,
auxiliaryCommentBefore,
sourceMaps: false,
});
require('fs').writeFileSync('./src/Options/Definitions.js', res.code + '\n');
require('fs').writeFileSync('./src/Options/docs.js', docs);
+3 -3
View File
@@ -1,11 +1,11 @@
{
"plugins": [
"transform-object-rest-spread"
"@babel/plugin-proposal-object-rest-spread"
],
"presets": [
["env", {
["@babel/preset-env", {
"targets": {
"node": "8"
"node": "14"
}
}]
],
+4 -1
View File
@@ -15,6 +15,7 @@
"equal": true,
"expectAsync": true,
"notEqual": true,
"it_id": true,
"it_only_db": true,
"it_only_mongodb_version": true,
"it_only_postgres_version": true,
@@ -27,6 +28,7 @@
"fit_exclude_node_version": true,
"it_exclude_dbs": true,
"describe_only_db": true,
"fdescribe_only_db": true,
"describe_only": true,
"on_db": true,
"defaultConfiguration": true,
@@ -34,7 +36,8 @@
"jequal": true,
"create": true,
"arrayContains": true,
"databaseAdapter": true
"databaseAdapter": true,
"databaseURI": true
},
"rules": {
"no-console": [0],
+22 -4
View File
@@ -1,6 +1,5 @@
const loadAdapter = require('../lib/Adapters/AdapterLoader').loadAdapter;
const { loadAdapter, loadModule } = require('../lib/Adapters/AdapterLoader');
const FilesAdapter = require('@parse/fs-files-adapter').default;
const ParsePushAdapter = require('@parse/push-adapter').default;
const MockFilesAdapter = require('mock-files-adapter');
const Config = require('../lib/Config');
@@ -103,19 +102,19 @@ describe('AdapterLoader', () => {
done();
});
it('should load push adapter from options', done => {
it('should load push adapter from options', async () => {
const options = {
android: {
senderId: 'yolo',
apiKey: 'yolo',
},
};
const ParsePushAdapter = await loadModule('@parse/push-adapter');
expect(() => {
const adapter = loadAdapter(undefined, ParsePushAdapter, options);
expect(adapter.constructor).toBe(ParsePushAdapter);
expect(adapter).not.toBe(undefined);
}).not.toThrow();
done();
});
it('should load custom push adapter from string (#3544)', done => {
@@ -142,6 +141,25 @@ describe('AdapterLoader', () => {
}).not.toThrow();
});
it('should load custom database adapter from config', done => {
const adapterPath = require('path').resolve('./spec/support/MockDatabaseAdapter');
const options = {
databaseURI: 'oracledb://user:password@localhost:1521/freepdb1',
collectionPrefix: '',
};
const databaseAdapterOptions = {
adapter: adapterPath,
options,
};
expect(() => {
const databaseAdapter = loadAdapter(databaseAdapterOptions);
expect(databaseAdapter).not.toBe(undefined);
expect(databaseAdapter.options).toEqual(options);
expect(databaseAdapter.getDatabaseURI()).toEqual(options.databaseURI);
}).not.toThrow();
done();
});
it('should load file adapter from direct passing', done => {
spyOn(console, 'warn').and.callFake(() => {});
const mockFilesAdapter = new MockFilesAdapter('key', 'secret', 'bucket');
+42 -32
View File
@@ -1,11 +1,10 @@
const AggregateRouter = require('../lib/Routers/AggregateRouter').AggregateRouter;
describe('AggregateRouter', () => {
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Array', () => {
const body = [
{
group: { objectId: {} },
$group: { _id: {} },
},
];
const expected = [{ $group: { _id: {} } }];
@@ -13,22 +12,20 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Object', () => {
const body = {
group: { objectId: {} },
$group: { _id: {} },
};
const expected = [{ $group: { _id: {} } }];
const result = AggregateRouter.getPipeline(body);
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Pipeline Operator (Array)', () => {
const body = {
pipeline: [
{
group: { objectId: {} },
$group: { _id: {} },
},
],
};
@@ -37,11 +34,10 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline from Pipeline Operator (Object)', () => {
const body = {
pipeline: {
group: { objectId: {} },
$group: { _id: {} },
},
};
const expected = [{ $group: { _id: {} } }];
@@ -49,43 +45,42 @@ describe('AggregateRouter', () => {
expect(result).toEqual(expected);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline fails multiple keys in Array stage ', () => {
const body = [
{
group: { objectId: {} },
match: { name: 'Test' },
$group: { _id: {} },
$match: { name: 'Test' },
},
];
try {
AggregateRouter.getPipeline(body);
} catch (e) {
expect(e.message).toBe('Pipeline stages should only have one key found group, match');
}
expect(() => AggregateRouter.getPipeline(body)).toThrow(
new Parse.Error(
Parse.Error.INVALID_QUERY,
'Pipeline stages should only have one key but found $group, $match.'
)
);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get pipeline fails multiple keys in Pipeline Operator Array stage ', () => {
const body = {
pipeline: [
{
group: { objectId: {} },
match: { name: 'Test' },
$group: { _id: {} },
$match: { name: 'Test' },
},
],
};
try {
AggregateRouter.getPipeline(body);
} catch (e) {
expect(e.message).toBe('Pipeline stages should only have one key found group, match');
}
expect(() => AggregateRouter.getPipeline(body)).toThrow(
new Parse.Error(
Parse.Error.INVALID_QUERY,
'Pipeline stages should only have one key but found $group, $match.'
)
);
});
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
it('get search pipeline from Pipeline Operator (Array)', () => {
const body = {
pipeline: {
search: {},
$search: {},
},
};
const expected = [{ $search: {} }];
@@ -105,7 +100,7 @@ describe('AggregateRouter', () => {
it('support nested stage names starting with `$`', () => {
const body = [
{
lookup: {
$lookup: {
from: 'ACollection',
let: { id: '_id' },
as: 'results',
@@ -145,11 +140,11 @@ describe('AggregateRouter', () => {
it('support the use of `_id` in stages', () => {
const body = [
{ match: { _id: 'randomId' } },
{ sort: { _id: -1 } },
{ addFields: { _id: 1 } },
{ group: { _id: {} } },
{ project: { _id: 0 } },
{ $match: { _id: 'randomId' } },
{ $sort: { _id: -1 } },
{ $addFields: { _id: 1 } },
{ $group: { _id: {} } },
{ $project: { _id: 0 } },
];
const expected = [
{ $match: { _id: 'randomId' } },
@@ -161,4 +156,19 @@ describe('AggregateRouter', () => {
const result = AggregateRouter.getPipeline(body);
expect(result).toEqual(expected);
});
it('should throw with invalid stage', () => {
expect(() => AggregateRouter.getPipeline([{ foo: 'bar' }])).toThrow(
new Parse.Error(Parse.Error.INVALID_QUERY, `Invalid aggregate stage 'foo'.`)
);
});
it('should throw with invalid group', () => {
expect(() => AggregateRouter.getPipeline([{ $group: { objectId: 'bar' } }])).toThrow(
new Parse.Error(
Parse.Error.INVALID_QUERY,
`Cannot use 'objectId' in aggregation stage $group.`
)
);
});
});
+6 -2
View File
@@ -339,11 +339,12 @@ describe('AudiencesRouter', () => {
)
.then(result => {
expect(result).toBeTruthy();
database
.collection('test__Audience')
.find({ _id: audience.objectId })
.toArray((error, rows) => {
expect(error).toEqual(undefined);
.toArray()
.then(rows => {
expect(rows[0]['times_used']).toEqual(1);
expect(rows[0]['_last_used']).toEqual(now);
Parse._request(
@@ -362,6 +363,9 @@ describe('AudiencesRouter', () => {
.catch(error => {
done.fail(error);
});
})
.catch(error => {
done.fail(error);
});
});
});
+48 -9
View File
@@ -81,17 +81,35 @@ describe('Auth', () => {
.then(roles => expect(roles).toEqual([]))
.then(() => done());
});
});
it('should properly handle bcrypt upgrade', done => {
const bcryptOriginal = require('bcrypt-nodejs');
const bcryptNew = require('bcryptjs');
bcryptOriginal.hash('my1Long:password', null, null, function (err, res) {
bcryptNew.compare('my1Long:password', res, function (err, res) {
expect(res).toBeTruthy();
done();
});
});
it('can use extendSessionOnUse', async () => {
await reconfigureServer({
extendSessionOnUse: true,
});
const user = new Parse.User();
await user.signUp({
username: 'hello',
password: 'password',
});
const session = await new Parse.Query(Parse.Session).first();
const updatedAt = new Date('2010');
const expiry = new Date();
expiry.setHours(expiry.getHours() + 1);
await Parse.Server.database.update(
'_Session',
{ objectId: session.id },
{
expiresAt: { __type: 'Date', iso: expiry.toISOString() },
updatedAt: updatedAt.toISOString(),
}
);
await session.fetch();
await new Promise(resolve => setTimeout(resolve, 1000));
await session.fetch();
expect(session.get('expiresAt') > expiry).toBeTrue();
});
it('should load auth without a config', async () => {
@@ -242,3 +260,24 @@ describe('Auth', () => {
});
});
});
describe('extendSessionOnUse', () => {
it(`shouldUpdateSessionExpiry()`, async () => {
const { shouldUpdateSessionExpiry } = require('../lib/Auth');
let update = new Date(Date.now() - 86410 * 1000);
const res = shouldUpdateSessionExpiry(
{ sessionLength: 86460 },
{ updatedAt: update }
);
update = new Date(Date.now() - 43210 * 1000);
const res2 = shouldUpdateSessionExpiry(
{ sessionLength: 86460 },
{ updatedAt: update }
);
expect(res).toBe(true);
expect(res2).toBe(false);
});
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+66 -38
View File
@@ -74,7 +74,7 @@ describe('commander additions', () => {
done();
});
it('should load properly use args over env', done => {
it('should load properly use args over env', () => {
commander.loadDefinitions(testDefinitions);
commander.parse(['node', './CLI.spec.js', '--arg0', 'arg0Value', '--arg4', ''], {
PROGRAM_ARG_0: 'arg0ENVValue',
@@ -86,7 +86,6 @@ describe('commander additions', () => {
expect(commander.arg1).toEqual('arg1ENVValue');
expect(commander.arg2).toEqual(4);
expect(commander.arg4).toEqual('');
done();
});
it('should fail in action as port is invalid', done => {
@@ -219,17 +218,14 @@ describe('execution', () => {
}
});
it('shoud start Parse Server', done => {
childProcess = spawn(binPath, [
'--appId',
'test',
'--masterKey',
'test',
'--databaseURI',
'mongodb://localhost/test',
'--port',
'1339',
]);
it('should start Parse Server', done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
childProcess = spawn(
binPath,
['--appId', 'test', '--masterKey', 'test', '--databaseURI', databaseURI, '--port', '1339'],
{ env }
);
childProcess.stdout.on('data', data => {
data = data.toString();
if (data.includes('parse-server running on')) {
@@ -241,18 +237,24 @@ describe('execution', () => {
});
});
it('shoud start Parse Server with GraphQL', done => {
childProcess = spawn(binPath, [
'--appId',
'test',
'--masterKey',
'test',
'--databaseURI',
'mongodb://localhost/test',
'--port',
'1340',
'--mountGraphQL',
]);
it('should start Parse Server with GraphQL', async done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
childProcess = spawn(
binPath,
[
'--appId',
'test',
'--masterKey',
'test',
'--databaseURI',
databaseURI,
'--port',
'1340',
'--mountGraphQL',
],
{ env }
);
let output = '';
childProcess.stdout.on('data', data => {
data = data.toString();
@@ -267,19 +269,25 @@ describe('execution', () => {
});
});
it('shoud start Parse Server with GraphQL and Playground', done => {
childProcess = spawn(binPath, [
'--appId',
'test',
'--masterKey',
'test',
'--databaseURI',
'mongodb://localhost/test',
'--port',
'1341',
'--mountGraphQL',
'--mountPlayground',
]);
it('should start Parse Server with GraphQL and Playground', async done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
childProcess = spawn(
binPath,
[
'--appId',
'test',
'--masterKey',
'test',
'--databaseURI',
databaseURI,
'--port',
'1341',
'--mountGraphQL',
'--mountPlayground',
],
{ env }
);
let output = '';
childProcess.stdout.on('data', data => {
data = data.toString();
@@ -294,4 +302,24 @@ describe('execution', () => {
done.fail(data.toString());
});
});
it('can start Parse Server with auth via CLI', done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
childProcess = spawn(
binPath,
['--databaseURI', databaseURI, './spec/configs/CLIConfigAuth.json'],
{ env }
);
childProcess.stdout.on('data', data => {
data = data.toString();
if (data.includes('parse-server running on')) {
done();
}
});
childProcess.stderr.on('data', data => {
data = data.toString();
done.fail(data.toString());
});
});
});
+272 -87
View File
@@ -1,6 +1,7 @@
'use strict';
const Config = require('../lib/Config');
const Parse = require('parse/node');
const ParseServer = require('../lib/index').ParseServer;
const request = require('../lib/request');
const InMemoryCacheAdapter = require('../lib/Adapters/Cache/InMemoryCacheAdapter')
.InMemoryCacheAdapter;
@@ -39,6 +40,47 @@ describe('Cloud Code', () => {
});
});
it('can load cloud code as a module', async () => {
process.env.npm_package_type = 'module';
await reconfigureServer({ appId: 'test1', 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('cloud code must be valid type', async () => {
await expectAsync(reconfigureServer({ cloud: true })).toBeRejectedWith(
"argument 'cloud' must either be a string or a function"
);
});
it('should wait for cloud code to load', async () => {
await reconfigureServer({ appId: 'test3' });
const initiated = new Date();
const parseServer = await new ParseServer({
...defaultConfiguration,
appId: 'test3',
masterKey: 'test',
serverURL: 'http://localhost:12668/parse',
async cloud() {
await new Promise(resolve => setTimeout(resolve, 1000));
Parse.Cloud.beforeSave('Test', () => {
throw 'Cannot save.';
});
},
}).start();
const express = require('express');
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12668);
const now = new Date();
expect(now.getTime() - initiated.getTime() > 1000).toBeTrue();
await expectAsync(new Parse.Object('Test').save()).toBeRejectedWith(
new Parse.Error(141, 'Cannot save.')
);
await new Promise(resolve => server.close(resolve));
});
it('can create functions', done => {
Parse.Cloud.define('hello', () => {
return 'Hello world!';
@@ -50,6 +92,25 @@ describe('Cloud Code', () => {
});
});
it('can get config', () => {
const config = Parse.Server;
let currentConfig = Config.get('test');
const server = require('../lib/cloud-code/Parse.Server');
expect(Object.keys(config)).toEqual(Object.keys({ ...currentConfig, ...server }));
config.silent = false;
Parse.Server = config;
currentConfig = Config.get('test');
expect(currentConfig.silent).toBeFalse();
});
it('can get curent version', () => {
const version = require('../package.json').version;
const currentConfig = Config.get('test');
expect(Parse.Server.version).toBeDefined();
expect(currentConfig.version).toBeDefined();
expect(Parse.Server.version).toEqual(version);
});
it('show warning on duplicate cloud functions', done => {
const logger = require('../lib/logger').logger;
spyOn(logger, 'warn').and.callFake(() => {});
@@ -1300,6 +1361,48 @@ describe('Cloud Code', () => {
});
});
it('should not encode Parse Objects', async () => {
await reconfigureServer({ encodeParseObjectInCloudFunction: false });
const user = new Parse.User();
user.setUsername('username');
user.setPassword('password');
user.set('deleted', false);
await user.signUp();
Parse.Cloud.define(
'deleteAccount',
async req => {
expect(req.params.object instanceof Parse.Object).not.toBeTrue();
return 'Object deleted';
},
{
requireMaster: true,
}
);
await Parse.Cloud.run('deleteAccount', { object: user.toPointer() }, { useMasterKey: true });
});
it('allow cloud to encode Parse Objects', async () => {
await reconfigureServer({ encodeParseObjectInCloudFunction: true });
const user = new Parse.User();
user.setUsername('username');
user.setPassword('password');
user.set('deleted', false);
await user.signUp();
Parse.Cloud.define(
'deleteAccount',
async req => {
expect(req.params.object instanceof Parse.Object).toBeTrue();
req.params.object.set('deleted', true);
await req.params.object.save(null, { useMasterKey: true });
return 'Object deleted';
},
{
requireMaster: true,
}
);
await Parse.Cloud.run('deleteAccount', { object: user.toPointer() }, { useMasterKey: true });
});
it('beforeSave should not affect fetched pointers', done => {
Parse.Cloud.beforeSave('BeforeSaveUnchanged', () => {});
@@ -1548,6 +1651,22 @@ describe('Cloud Code', () => {
expect(obj.get('foo')).toBe('bar');
});
it('create role with name and ACL and a beforeSave', async () => {
Parse.Cloud.beforeSave(Parse.Role, ({ object }) => {
return object;
});
const obj = new Parse.Role('TestRole', new Parse.ACL({ '*': { read: true, write: true } }));
await obj.save();
expect(obj.getACL()).toEqual(new Parse.ACL({ '*': { read: true, write: true } }));
expect(obj.get('name')).toEqual('TestRole');
await obj.fetch();
expect(obj.getACL()).toEqual(new Parse.ACL({ '*': { read: true, write: true } }));
expect(obj.get('name')).toEqual('TestRole');
});
it('can unset in afterSave', async () => {
Parse.Cloud.beforeSave('TestObject', ({ object }) => {
if (!object.existed()) {
@@ -1676,25 +1795,6 @@ describe('Cloud Code', () => {
obj.save().then(done, done.fail);
});
it('can deprecate Parse.Cloud.httpRequest', async () => {
const logger = require('../lib/logger').logger;
spyOn(logger, 'warn').and.callFake(() => {});
Parse.Cloud.define('hello', () => {
return 'Hello world!';
});
await Parse.Cloud.httpRequest({
method: 'POST',
url: 'http://localhost:8378/1/functions/hello',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
},
});
expect(logger.warn).toHaveBeenCalledWith(
'DeprecationWarning: Parse.Cloud.httpRequest is deprecated and will be removed in a future version. Use a http request library instead.'
);
});
describe('cloud jobs', () => {
it('should define a job', done => {
expect(() => {
@@ -2299,6 +2399,56 @@ describe('beforeFind hooks', () => {
});
});
it('sets correct beforeFind trigger isGet parameter for Parse.Object.fetch request', async () => {
const hook = {
method: req => {
expect(req.isGet).toEqual(true);
return Promise.resolve();
},
};
spyOn(hook, 'method').and.callThrough();
Parse.Cloud.beforeFind('MyObject', hook.method);
const obj = new Parse.Object('MyObject');
await obj.save();
const getObj = await obj.fetch();
expect(getObj).toBeInstanceOf(Parse.Object);
expect(hook.method).toHaveBeenCalledTimes(1);
});
it('sets correct beforeFind trigger isGet parameter for Parse.Query.get request', async () => {
const hook = {
method: req => {
expect(req.isGet).toEqual(false);
return Promise.resolve();
},
};
spyOn(hook, 'method').and.callThrough();
Parse.Cloud.beforeFind('MyObject', hook.method);
const obj = new Parse.Object('MyObject');
await obj.save();
const query = new Parse.Query('MyObject');
const getObj = await query.get(obj.id);
expect(getObj).toBeInstanceOf(Parse.Object);
expect(hook.method).toHaveBeenCalledTimes(1);
});
it('sets correct beforeFind trigger isGet parameter for Parse.Query.find request', async () => {
const hook = {
method: req => {
expect(req.isGet).toEqual(false);
return Promise.resolve();
},
};
spyOn(hook, 'method').and.callThrough();
Parse.Cloud.beforeFind('MyObject', hook.method);
const obj = new Parse.Object('MyObject');
await obj.save();
const query = new Parse.Query('MyObject');
const findObjs = await query.find();
expect(findObjs?.[0]).toBeInstanceOf(Parse.Object);
expect(hook.method).toHaveBeenCalledTimes(1);
});
it('should have request headers', done => {
Parse.Cloud.beforeFind('MyObject', req => {
expect(req.headers).toBeDefined();
@@ -2332,6 +2482,60 @@ describe('beforeFind hooks', () => {
})
.then(() => done());
});
it('should run beforeFind on pointers and array of pointers from an object', async () => {
const obj1 = new Parse.Object('TestObject');
const obj2 = new Parse.Object('TestObject2');
const obj3 = new Parse.Object('TestObject');
obj2.set('aField', 'aFieldValue');
await obj2.save();
obj1.set('pointerField', obj2);
obj3.set('pointerFieldArray', [obj2]);
await obj1.save();
await obj3.save();
const spy = jasmine.createSpy('beforeFindSpy');
Parse.Cloud.beforeFind('TestObject2', spy);
const query = new Parse.Query('TestObject');
await query.get(obj1.id);
// Pointer not included in query so we don't expect beforeFind to be called
expect(spy).not.toHaveBeenCalled();
const query2 = new Parse.Query('TestObject');
query2.include('pointerField');
const res = await query2.get(obj1.id);
expect(res.get('pointerField').get('aField')).toBe('aFieldValue');
// Pointer included in query so we expect beforeFind to be called
expect(spy).toHaveBeenCalledTimes(1);
const query3 = new Parse.Query('TestObject');
query3.include('pointerFieldArray');
const res2 = await query3.get(obj3.id);
expect(res2.get('pointerFieldArray')[0].get('aField')).toBe('aFieldValue');
expect(spy).toHaveBeenCalledTimes(2);
});
it('should have access to context in include query in beforeFind hook', async () => {
let beforeFindTestObjectCalled = false;
let beforeFindTestObject2Called = false;
const obj1 = new Parse.Object('TestObject');
const obj2 = new Parse.Object('TestObject2');
obj2.set('aField', 'aFieldValue');
await obj2.save();
obj1.set('pointerField', obj2);
await obj1.save();
Parse.Cloud.beforeFind('TestObject', req => {
expect(req.context).toBeDefined();
expect(req.context.a).toEqual('a');
beforeFindTestObjectCalled = true;
});
Parse.Cloud.beforeFind('TestObject2', req => {
expect(req.context).toBeDefined();
expect(req.context.a).toEqual('a');
beforeFindTestObject2Called = true;
});
const query = new Parse.Query('TestObject');
await query.include('pointerField').find({ context: { a: 'a' } });
expect(beforeFindTestObjectCalled).toBeTrue();
expect(beforeFindTestObject2Called).toBeTrue();
});
});
describe('afterFind hooks', () => {
@@ -2725,7 +2929,7 @@ describe('afterFind hooks', () => {
const obj = new Parse.Object('MyObject');
const pipeline = [
{
group: { objectId: {} },
$group: { _id: {} },
},
];
obj
@@ -3112,6 +3316,36 @@ describe('beforeLogin hook', () => {
done();
});
it('does not crash server when throwing in afterLogin hook', async () => {
const error = new Parse.Error(2000, 'afterLogin error');
const trigger = {
afterLogin() {
throw error;
},
};
const spy = spyOn(trigger, 'afterLogin').and.callThrough();
Parse.Cloud.afterLogin(trigger.afterLogin);
await Parse.User.signUp('user', 'pass');
const response = await Parse.User.logIn('user', 'pass').catch(e => e);
expect(spy).toHaveBeenCalled();
expect(response).toEqual(error);
});
it('does not crash server when throwing in afterLogout hook', async () => {
const error = new Parse.Error(2000, 'afterLogout error');
const trigger = {
afterLogout() {
throw error;
},
};
const spy = spyOn(trigger, 'afterLogout').and.callThrough();
Parse.Cloud.afterLogout(trigger.afterLogout);
await Parse.User.signUp('user', 'pass');
const response = await Parse.User.logOut().catch(e => e);
expect(spy).toHaveBeenCalled();
expect(response).toEqual(error);
});
it('should have expected data in request', async done => {
Parse.Cloud.beforeLogin(req => {
expect(req.object).toBeDefined();
@@ -3119,7 +3353,7 @@ describe('beforeLogin hook', () => {
expect(req.headers).toBeDefined();
expect(req.ip).toBeDefined();
expect(req.installationId).toBeDefined();
expect(req.context).toBeUndefined();
expect(req.context).toBeDefined();
});
await Parse.User.signUp('tupac', 'shakur');
@@ -3236,7 +3470,7 @@ describe('afterLogin hook', () => {
expect(req.headers).toBeDefined();
expect(req.ip).toBeDefined();
expect(req.installationId).toBeDefined();
expect(req.context).toBeUndefined();
expect(req.context).toBeDefined();
});
await Parse.User.signUp('testuser', 'p@ssword');
@@ -3402,7 +3636,7 @@ describe('afterLogin hook', () => {
});
describe('saveFile hooks', () => {
it('beforeSaveFile should return file that is already saved and not save anything to files adapter', async () => {
it('beforeSave(Parse.File) should return file that is already saved and not save anything to files adapter', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSave(Parse.File, () => {
@@ -3418,7 +3652,7 @@ describe('saveFile hooks', () => {
expect(createFileSpy).not.toHaveBeenCalled();
});
it('beforeSaveFile should throw error', async () => {
it('beforeSave(Parse.File) should throw error', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSave(Parse.File, () => {
throw new Parse.Error(400, 'some-error-message');
@@ -3431,7 +3665,7 @@ describe('saveFile hooks', () => {
}
});
it('beforeSaveFile should change values of uploaded file by editing fileObject directly', async () => {
it('beforeSave(Parse.File) should change values of uploaded file by editing fileObject directly', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSave(Parse.File, async req => {
@@ -3460,7 +3694,7 @@ describe('saveFile hooks', () => {
);
});
it('beforeSaveFile should change values by returning new fileObject', async () => {
it('beforeSave(Parse.File) should change values by returning new fileObject', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSave(Parse.File, async req => {
@@ -3494,7 +3728,7 @@ describe('saveFile hooks', () => {
expect(file._name.indexOf(expectedFileName)).toBe(file._name.length - expectedFileName.length);
});
it('beforeSaveFile should contain metadata and tags saved from client', async () => {
it('beforeSave(Parse.File) should contain metadata and tags saved from client', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSave(Parse.File, async req => {
@@ -3522,7 +3756,7 @@ describe('saveFile hooks', () => {
);
});
it('beforeSaveFile should return same file data with new file name', async () => {
it('beforeSave(Parse.File) should return same file data with new file name', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const config = Config.get('test');
config.filesController.options.preserveFileName = true;
@@ -3537,7 +3771,7 @@ describe('saveFile hooks', () => {
expect(result.name()).toBe('2020-04-01.txt');
});
it('afterSaveFile should set fileSize to null if beforeSave returns an already saved file', async () => {
it('afterSave(Parse.File) should set fileSize to null if beforeSave returns an already saved file', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSave(Parse.File, req => {
@@ -3557,7 +3791,7 @@ describe('saveFile hooks', () => {
expect(createFileSpy).not.toHaveBeenCalled();
});
it('afterSaveFile should throw error', async () => {
it('afterSave(Parse.File) should throw error', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.afterSave(Parse.File, async () => {
throw new Parse.Error(400, 'some-error-message');
@@ -3571,7 +3805,7 @@ describe('saveFile hooks', () => {
}
});
it('afterSaveFile should call with fileObject', async done => {
it('afterSave(Parse.File) should call with fileObject', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSave(Parse.File, async req => {
req.file.setTags({ tagA: 'some-tag' });
@@ -3587,7 +3821,7 @@ describe('saveFile hooks', () => {
await file.save({ useMasterKey: true });
});
it('afterSaveFile should change fileSize when file data changes', async done => {
it('afterSave(Parse.File) should change fileSize when file data changes', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSave(Parse.File, async req => {
expect(req.fileSize).toBe(3);
@@ -3604,7 +3838,7 @@ describe('saveFile hooks', () => {
await file.save({ useMasterKey: true });
});
it('beforeDeleteFile should call with fileObject', async () => {
it('beforeDelete(Parse.File) should call with fileObject', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeDelete(Parse.File, req => {
expect(req.file).toBeInstanceOf(Parse.File);
@@ -3616,7 +3850,7 @@ describe('saveFile hooks', () => {
await file.destroy({ useMasterKey: true });
});
it('beforeDeleteFile should throw error', async done => {
it('beforeDelete(Parse.File) should throw error', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeDelete(Parse.File, () => {
throw new Error('some error message');
@@ -3630,7 +3864,7 @@ describe('saveFile hooks', () => {
}
});
it('afterDeleteFile should call with fileObject', async done => {
it('afterDelete(Parse.File) should call with fileObject', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeDelete(Parse.File, req => {
expect(req.file).toBeInstanceOf(Parse.File);
@@ -3647,7 +3881,7 @@ describe('saveFile hooks', () => {
await file.destroy({ useMasterKey: true });
});
it('beforeSaveFile should not change file if nothing is returned', async () => {
it('beforeSave(Parse.File) should not change file if nothing is returned', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSave(Parse.File, () => {
return;
@@ -3657,7 +3891,7 @@ describe('saveFile hooks', () => {
expect(result).toBe(file);
});
it('throw custom error from beforeSaveFile', async done => {
it('throw custom error from beforeSave(Parse.File) ', async done => {
Parse.Cloud.beforeSave(Parse.File, () => {
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'It should fail');
});
@@ -3671,7 +3905,7 @@ describe('saveFile hooks', () => {
}
});
it('throw empty error from beforeSaveFile', async done => {
it('throw empty error from beforeSave(Parse.File)', async done => {
Parse.Cloud.beforeSave(Parse.File, () => {
throw null;
});
@@ -3684,55 +3918,6 @@ describe('saveFile hooks', () => {
done();
}
});
it('legacy hooks', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'warn').and.callFake(() => {});
const triggers = {
beforeSaveFile(req) {
req.file.setTags({ tagA: 'some-tag' });
req.file.setMetadata({ foo: 'bar' });
expect(req.triggerName).toEqual('beforeSave');
expect(req.master).toBe(true);
},
afterSaveFile(req) {
expect(req.master).toBe(true);
expect(req.file._tags).toEqual({ tagA: 'some-tag' });
expect(req.file._metadata).toEqual({ foo: 'bar' });
},
beforeDeleteFile(req) {
expect(req.file).toBeInstanceOf(Parse.File);
expect(req.file._name).toEqual('popeye.txt');
expect(req.file._url).toEqual('http://www.somewhere.com/popeye.txt');
expect(req.fileSize).toBe(null);
},
afterDeleteFile(req) {
expect(req.file).toBeInstanceOf(Parse.File);
expect(req.file._name).toEqual('popeye.txt');
expect(req.file._url).toEqual('http://www.somewhere.com/popeye.txt');
},
};
for (const key in triggers) {
spyOn(triggers, key).and.callThrough();
Parse.Cloud[key](triggers[key]);
}
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save({ useMasterKey: true });
await new Parse.File('popeye.txt', [1, 2, 3], 'text/plain').destroy({ useMasterKey: true });
await new Promise(resolve => setTimeout(resolve, 100));
for (const key in triggers) {
expect(triggers[key]).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`DeprecationWarning: Parse.Cloud.${key} is deprecated and will be removed in a future version. Use Parse.Cloud.${key.replace(
'File',
''
)}(Parse.File, (request) => {})`
);
}
});
});
describe('sendEmail', () => {
+127
View File
@@ -15,6 +15,13 @@ describe('Cloud Code Logger', () => {
// useful to flip to false for fine tuning :).
silent: true,
logLevel: undefined,
logLevels: {
cloudFunctionError: 'error',
cloudFunctionSuccess: 'info',
triggerAfter: 'info',
triggerBeforeError: 'error',
triggerBeforeSuccess: 'info',
},
})
.then(() => {
return Parse.User.signUp('tester', 'abc')
@@ -182,6 +189,77 @@ describe('Cloud Code Logger', () => {
});
});
it('should log cloud function execution using the custom log level', async done => {
Parse.Cloud.define('aFunction', () => {
return 'it worked!';
});
Parse.Cloud.define('bFunction', () => {
throw new Error('Failed');
});
await Parse.Cloud.run('aFunction', { foo: 'bar' }).then(() => {
const log = spy.calls.allArgs().find(log => log[1].startsWith('Ran cloud function '))?.[0];
expect(log).toEqual('info');
});
await reconfigureServer({
silent: true,
logLevels: {
cloudFunctionSuccess: 'warn',
cloudFunctionError: 'info',
},
});
spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough();
try {
await Parse.Cloud.run('bFunction', { foo: 'bar' });
throw new Error('bFunction should have failed');
} catch {
const log = spy.calls
.allArgs()
.find(log => log[1].startsWith('Failed running cloud function bFunction for '))?.[0];
expect(log).toEqual('info');
done();
}
});
it('should log cloud function triggers using the custom log level', async () => {
Parse.Cloud.beforeSave('TestClass', () => {});
Parse.Cloud.afterSave('TestClass', () => {});
const execTest = async (logLevel, triggerBeforeSuccess, triggerAfter) => {
await reconfigureServer({
silent: true,
logLevel,
logLevels: {
triggerAfter,
triggerBeforeSuccess,
},
});
spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough();
const obj = new Parse.Object('TestClass');
await obj.save();
return {
beforeSave: spy.calls
.allArgs()
.find(log => log[1].startsWith('beforeSave triggered for TestClass for user '))?.[0],
afterSave: spy.calls
.allArgs()
.find(log => log[1].startsWith('afterSave triggered for TestClass for user '))?.[0],
};
};
let calls = await execTest('silly', 'silly', 'debug');
expect(calls).toEqual({ beforeSave: 'silly', afterSave: 'debug' });
calls = await execTest('info', 'warn', 'debug');
expect(calls).toEqual({ beforeSave: 'warn', afterSave: undefined });
});
it('should log cloud function failure', done => {
Parse.Cloud.define('aFunction', () => {
throw 'it failed!';
@@ -263,4 +341,53 @@ describe('Cloud Code Logger', () => {
expect(args[0]).toBe('Parse error: ');
expect(args[1].message).toBe('Object not found.');
});
it('should log cloud function execution using the silent log level', async () => {
await reconfigureServer({
logLevels: {
cloudFunctionSuccess: 'silent',
cloudFunctionError: 'silent',
},
});
Parse.Cloud.define('aFunction', () => {
return 'it worked!';
});
Parse.Cloud.define('bFunction', () => {
throw new Error('Failed');
});
spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough();
await Parse.Cloud.run('aFunction', { foo: 'bar' });
expect(spy).toHaveBeenCalledTimes(0);
await expectAsync(Parse.Cloud.run('bFunction', { foo: 'bar' })).toBeRejected();
// Not "Failed running cloud function message..."
expect(spy).toHaveBeenCalledTimes(1);
});
it('should log cloud function triggers using the silent log level', async () => {
await reconfigureServer({
logLevels: {
triggerAfter: 'silent',
triggerBeforeSuccess: 'silent',
triggerBeforeError: 'silent',
},
});
Parse.Cloud.beforeSave('TestClassError', () => {
throw new Error('Failed');
});
Parse.Cloud.beforeSave('TestClass', () => {});
Parse.Cloud.afterSave('TestClass', () => {});
spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough();
const obj = new Parse.Object('TestClass');
await obj.save();
expect(spy).toHaveBeenCalledTimes(0);
const objError = new Parse.Object('TestClassError');
await expectAsync(objError.save()).toBeRejected();
// Not "beforeSave failed for TestClassError for user ..."
expect(spy).toHaveBeenCalledTimes(1);
});
});
+254
View File
@@ -1,3 +1,4 @@
const Config = require('../lib/Config');
const DatabaseController = require('../lib/Controllers/DatabaseController.js');
const validateQuery = DatabaseController._validateQuery;
@@ -361,6 +362,259 @@ describe('DatabaseController', function () {
done();
});
});
describe('enableCollationCaseComparison', () => {
const dummyStorageAdapter = {
find: () => Promise.resolve([]),
watch: () => Promise.resolve(),
getAllClasses: () => Promise.resolve([]),
};
beforeEach(() => {
Config.get(Parse.applicationId).schemaCache.clear();
});
it('should force caseInsensitive to false with enableCollationCaseComparison option', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {
enableCollationCaseComparison: true,
});
const spy = spyOn(dummyStorageAdapter, 'find');
spy.and.callThrough();
await databaseController.find('SomeClass', {}, { caseInsensitive: true });
expect(spy.calls.all()[0].args[3].caseInsensitive).toEqual(false);
});
it('should support caseInsensitive without enableCollationCaseComparison option', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {});
const spy = spyOn(dummyStorageAdapter, 'find');
spy.and.callThrough();
await databaseController.find('_User', {}, { caseInsensitive: true });
expect(spy.calls.all()[0].args[3].caseInsensitive).toEqual(true);
});
it_only_db('mongo')(
'should create insensitive indexes without enableCollationCaseComparison',
async () => {
await reconfigureServer({
databaseURI: 'mongodb://localhost:27017/enableCollationCaseComparisonFalse',
databaseAdapter: undefined,
});
const user = new Parse.User();
await user.save({
username: 'example',
password: 'password',
email: 'example@example.com',
});
const schemas = await Parse.Schema.all();
const UserSchema = schemas.find(({ className }) => className === '_User');
expect(UserSchema.indexes).toEqual({
_id_: { _id: 1 },
username_1: { username: 1 },
case_insensitive_username: { username: 1 },
case_insensitive_email: { email: 1 },
email_1: { email: 1 },
});
}
);
it_only_db('mongo')(
'should not create insensitive indexes with enableCollationCaseComparison',
async () => {
await reconfigureServer({
enableCollationCaseComparison: true,
databaseURI: 'mongodb://localhost:27017/enableCollationCaseComparisonTrue',
databaseAdapter: undefined,
});
const user = new Parse.User();
await user.save({
username: 'example',
password: 'password',
email: 'example@example.com',
});
const schemas = await Parse.Schema.all();
const UserSchema = schemas.find(({ className }) => className === '_User');
expect(UserSchema.indexes).toEqual({
_id_: { _id: 1 },
username_1: { username: 1 },
email_1: { email: 1 },
});
}
);
});
describe('convertEmailToLowercase', () => {
const dummyStorageAdapter = {
createObject: () => Promise.resolve({ ops: [{}] }),
findOneAndUpdate: () => Promise.resolve({}),
watch: () => Promise.resolve(),
getAllClasses: () =>
Promise.resolve([
{
className: '_User',
fields: { email: 'String' },
indexes: {},
classLevelPermissions: { protectedFields: {} },
},
]),
};
const dates = {
createdAt: { iso: undefined, __type: 'Date' },
updatedAt: { iso: undefined, __type: 'Date' },
};
it('should not transform email to lower case without convertEmailToLowercase option on create', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {});
const spy = spyOn(dummyStorageAdapter, 'createObject');
spy.and.callThrough();
await databaseController.create('_User', {
email: 'EXAMPLE@EXAMPLE.COM',
});
expect(spy.calls.all()[0].args[2]).toEqual({
email: 'EXAMPLE@EXAMPLE.COM',
...dates,
});
});
it('should transform email to lower case with convertEmailToLowercase option on create', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {
convertEmailToLowercase: true,
});
const spy = spyOn(dummyStorageAdapter, 'createObject');
spy.and.callThrough();
await databaseController.create('_User', {
email: 'EXAMPLE@EXAMPLE.COM',
});
expect(spy.calls.all()[0].args[2]).toEqual({
email: 'example@example.com',
...dates,
});
});
it('should not transform email to lower case without convertEmailToLowercase option on update', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {});
const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate');
spy.and.callThrough();
await databaseController.update('_User', { id: 'example' }, { email: 'EXAMPLE@EXAMPLE.COM' });
expect(spy.calls.all()[0].args[3]).toEqual({
email: 'EXAMPLE@EXAMPLE.COM',
});
});
it('should transform email to lower case with convertEmailToLowercase option on update', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {
convertEmailToLowercase: true,
});
const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate');
spy.and.callThrough();
await databaseController.update('_User', { id: 'example' }, { email: 'EXAMPLE@EXAMPLE.COM' });
expect(spy.calls.all()[0].args[3]).toEqual({
email: 'example@example.com',
});
});
it('should not find a case insensitive user by email with convertEmailToLowercase', async () => {
await reconfigureServer({ convertEmailToLowercase: true });
const user = new Parse.User();
await user.save({ username: 'EXAMPLE', email: 'EXAMPLE@EXAMPLE.COM', password: 'password' });
const query = new Parse.Query(Parse.User);
query.equalTo('email', 'EXAMPLE@EXAMPLE.COM');
const result = await query.find({ useMasterKey: true });
expect(result.length).toEqual(0);
const query2 = new Parse.Query(Parse.User);
query2.equalTo('email', 'example@example.com');
const result2 = await query2.find({ useMasterKey: true });
expect(result2.length).toEqual(1);
});
});
describe('convertUsernameToLowercase', () => {
const dummyStorageAdapter = {
createObject: () => Promise.resolve({ ops: [{}] }),
findOneAndUpdate: () => Promise.resolve({}),
watch: () => Promise.resolve(),
getAllClasses: () =>
Promise.resolve([
{
className: '_User',
fields: { username: 'String' },
indexes: {},
classLevelPermissions: { protectedFields: {} },
},
]),
};
const dates = {
createdAt: { iso: undefined, __type: 'Date' },
updatedAt: { iso: undefined, __type: 'Date' },
};
it('should not transform username to lower case without convertUsernameToLowercase option on create', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {});
const spy = spyOn(dummyStorageAdapter, 'createObject');
spy.and.callThrough();
await databaseController.create('_User', {
username: 'EXAMPLE',
});
expect(spy.calls.all()[0].args[2]).toEqual({
username: 'EXAMPLE',
...dates,
});
});
it('should transform username to lower case with convertUsernameToLowercase option on create', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {
convertUsernameToLowercase: true,
});
const spy = spyOn(dummyStorageAdapter, 'createObject');
spy.and.callThrough();
await databaseController.create('_User', {
username: 'EXAMPLE',
});
expect(spy.calls.all()[0].args[2]).toEqual({
username: 'example',
...dates,
});
});
it('should not transform username to lower case without convertUsernameToLowercase option on update', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {});
const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate');
spy.and.callThrough();
await databaseController.update('_User', { id: 'example' }, { username: 'EXAMPLE' });
expect(spy.calls.all()[0].args[3]).toEqual({
username: 'EXAMPLE',
});
});
it('should transform username to lower case with convertUsernameToLowercase option on update', async () => {
const databaseController = new DatabaseController(dummyStorageAdapter, {
convertUsernameToLowercase: true,
});
const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate');
spy.and.callThrough();
await databaseController.update('_User', { id: 'example' }, { username: 'EXAMPLE' });
expect(spy.calls.all()[0].args[3]).toEqual({
username: 'example',
});
});
it('should not find a case insensitive user by username with convertUsernameToLowercase', async () => {
await reconfigureServer({ convertUsernameToLowercase: true });
const user = new Parse.User();
await user.save({ username: 'EXAMPLE', password: 'password' });
const query = new Parse.Query(Parse.User);
query.equalTo('username', 'EXAMPLE');
const result = await query.find({ useMasterKey: true });
expect(result.length).toEqual(0);
const query2 = new Parse.Query(Parse.User);
query2.equalTo('username', 'example');
const result2 = await query2.find({ useMasterKey: true });
expect(result2.length).toEqual(1);
});
});
});
function buildCLP(pointerNames) {
+67 -2
View File
@@ -432,6 +432,42 @@ describe('DefinedSchemas', () => {
expect(testSchema.indexes).toBeUndefined();
expect(userSchema.indexes).toEqual(expectedIndexes);
});
it('should detect protected indexes for _User class', () => {
const definedSchema = new DefinedSchemas({}, {});
const protectedUserIndexes = ['_id_', 'case_insensitive_email', 'username_1', 'email_1'];
protectedUserIndexes.forEach(field => {
expect(definedSchema.isProtectedIndex('_User', field)).toEqual(true);
});
expect(definedSchema.isProtectedIndex('_User', 'test')).toEqual(false);
});
it('should detect protected indexes for _Role class', () => {
const definedSchema = new DefinedSchemas({}, {});
expect(definedSchema.isProtectedIndex('_Role', 'name_1')).toEqual(true);
expect(definedSchema.isProtectedIndex('_Role', 'test')).toEqual(false);
});
it('should detect protected indexes for _Idempotency class', () => {
const definedSchema = new DefinedSchemas({}, {});
expect(definedSchema.isProtectedIndex('_Idempotency', 'reqId_1')).toEqual(true);
expect(definedSchema.isProtectedIndex('_Idempotency', 'test')).toEqual(false);
});
it('should not detect protected indexes on user defined class', () => {
const definedSchema = new DefinedSchemas({}, {});
const protectedIndexes = [
'case_insensitive_email',
'username_1',
'email_1',
'reqId_1',
'name_1',
];
protectedIndexes.forEach(field => {
expect(definedSchema.isProtectedIndex('ExampleClass', field)).toEqual(false);
});
expect(definedSchema.isProtectedIndex('ExampleClass', '_id_')).toEqual(true);
});
});
describe('ClassLevelPermissions', () => {
@@ -518,7 +554,7 @@ describe('DefinedSchemas', () => {
});
});
it('should not delete automatically classes', async () => {
it('should not delete classes automatically', async () => {
await reconfigureServer({
schema: { definitions: [{ className: '_User' }, { className: 'Test' }] },
});
@@ -595,7 +631,7 @@ describe('DefinedSchemas', () => {
const logger = require('../lib/logger').logger;
spyOn(DefinedSchemas.prototype, 'wait').and.resolveTo();
spyOn(logger, 'error').and.callThrough();
spyOn(Parse.Schema, 'all').and.callFake(() => {
spyOn(DefinedSchemas.prototype, 'createDeleteSession').and.callFake(() => {
throw error;
});
@@ -641,4 +677,33 @@ describe('DefinedSchemas', () => {
expect(testSchema.classLevelPermissions.create).toEqual({ requiresAuthentication: true });
expect(logger.error).toHaveBeenCalledTimes(0);
});
it('should not affect cacheAdapter', async () => {
const server = await reconfigureServer();
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callThrough();
const migrationOptions = {
definitions: [
{
className: 'Test',
fields: { aField: { type: 'String' } },
indexes: { aField: { aField: 1 } },
classLevelPermissions: {
create: { requiresAuthentication: true },
},
},
],
};
const cacheAdapter = {
get: () => Promise.resolve(null),
put: () => {},
del: () => {},
clear: () => {},
connect: jasmine.createSpy('clear'),
};
server.config.cacheAdapter = cacheAdapter;
await new DefinedSchemas(migrationOptions, server.config).execute();
expect(cacheAdapter.connect).not.toHaveBeenCalled();
});
});
+287 -11
View File
@@ -1,7 +1,9 @@
'use strict';
const Auth = require('../lib/Auth');
const Config = require('../lib/Config');
const request = require('../lib/request');
const MockEmailAdapterWithOptions = require('./support/MockEmailAdapterWithOptions');
describe('Email Verification Token Expiration: ', () => {
it('show the invalid verification link page, if the user clicks on the verify email link after the email verify token expires', done => {
@@ -125,6 +127,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
request({
url: sendEmailOptions.link,
@@ -166,6 +169,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
request({
url: sendEmailOptions.link,
@@ -213,6 +217,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
request({
url: sendEmailOptions.link,
@@ -262,9 +267,14 @@ describe('Email Verification Token Expiration: ', () => {
})
.then(() => {
const config = Config.get('test');
return config.database.find('_User', {
username: 'sets_email_verify_token_expires_at',
});
return config.database.find(
'_User',
{
username: 'sets_email_verify_token_expires_at',
},
{},
Auth.maintenance(config)
);
})
.then(results => {
expect(results.length).toBe(1);
@@ -282,6 +292,223 @@ describe('Email Verification Token Expiration: ', () => {
});
});
it('can conditionally send emails', async () => {
let sendEmailOptions;
const emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
const verifyUserEmails = {
method(req) {
expect(Object.keys(req)).toEqual(['original', 'object', 'master', 'ip', 'installationId']);
return false;
},
};
const verifySpy = spyOn(verifyUserEmails, 'method').and.callThrough();
await reconfigureServer({
appName: 'emailVerifyToken',
verifyUserEmails: verifyUserEmails.method,
emailAdapter: emailAdapter,
emailVerifyTokenValidityDuration: 5, // 5 seconds
publicServerURL: 'http://localhost:8378/1',
});
const beforeSave = {
method(req) {
req.object.set('emailVerified', true);
},
};
const saveSpy = spyOn(beforeSave, 'method').and.callThrough();
const emailSpy = spyOn(emailAdapter, 'sendVerificationEmail').and.callThrough();
Parse.Cloud.beforeSave(Parse.User, beforeSave.method);
const user = new Parse.User();
user.setUsername('sets_email_verify_token_expires_at');
user.setPassword('expiringToken');
user.set('email', 'user@example.com');
await user.signUp();
const config = Config.get('test');
const results = await config.database.find(
'_User',
{
username: 'sets_email_verify_token_expires_at',
},
{},
Auth.maintenance(config)
);
expect(results.length).toBe(1);
const user_data = results[0];
expect(typeof user_data).toBe('object');
expect(user_data.emailVerified).toEqual(true);
expect(user_data._email_verify_token).toBeUndefined();
expect(user_data._email_verify_token_expires_at).toBeUndefined();
expect(emailSpy).not.toHaveBeenCalled();
expect(saveSpy).toHaveBeenCalled();
expect(sendEmailOptions).toBeUndefined();
expect(verifySpy).toHaveBeenCalled();
});
it('can conditionally send emails and allow conditional login', async () => {
let sendEmailOptions;
const emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
const verifyUserEmails = {
method(req) {
expect(Object.keys(req)).toEqual(['original', 'object', 'master', 'ip', 'installationId']);
if (req.object.get('username') === 'no_email') {
return false;
}
return true;
},
};
const verifySpy = spyOn(verifyUserEmails, 'method').and.callThrough();
await reconfigureServer({
appName: 'emailVerifyToken',
verifyUserEmails: verifyUserEmails.method,
preventLoginWithUnverifiedEmail: verifyUserEmails.method,
emailAdapter: emailAdapter,
emailVerifyTokenValidityDuration: 5, // 5 seconds
publicServerURL: 'http://localhost:8378/1',
});
const user = new Parse.User();
user.setUsername('no_email');
user.setPassword('expiringToken');
user.set('email', 'user@example.com');
await user.signUp();
expect(sendEmailOptions).toBeUndefined();
expect(user.getSessionToken()).toBeDefined();
expect(verifySpy).toHaveBeenCalledTimes(2);
const user2 = new Parse.User();
user2.setUsername('email');
user2.setPassword('expiringToken');
user2.set('email', 'user2@example.com');
await user2.signUp();
await jasmine.timeout();
expect(user2.getSessionToken()).toBeUndefined();
expect(sendEmailOptions).toBeDefined();
expect(verifySpy).toHaveBeenCalledTimes(5);
});
it('can conditionally send user email verification', async () => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
const sendVerificationEmail = {
method(req) {
expect(req.user).toBeDefined();
expect(req.master).toBeDefined();
return false;
},
};
const sendSpy = spyOn(sendVerificationEmail, 'method').and.callThrough();
await reconfigureServer({
appName: 'emailVerifyToken',
verifyUserEmails: true,
emailAdapter: emailAdapter,
emailVerifyTokenValidityDuration: 5, // 5 seconds
publicServerURL: 'http://localhost:8378/1',
sendUserEmailVerification: sendVerificationEmail.method,
});
const emailSpy = spyOn(emailAdapter, 'sendVerificationEmail').and.callThrough();
const newUser = new Parse.User();
newUser.setUsername('unsets_email_verify_token_expires_at');
newUser.setPassword('expiringToken');
newUser.set('email', 'user@example.com');
await newUser.signUp();
await Parse.User.requestEmailVerification('user@example.com');
await jasmine.timeout();
expect(sendSpy).toHaveBeenCalledTimes(2);
expect(emailSpy).toHaveBeenCalledTimes(0);
});
it('provides full user object in email verification function on email and username change', async () => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
const sendVerificationEmail = {
method(req) {
expect(req.user).toBeDefined();
expect(req.user.id).toBeDefined();
expect(req.user.get('createdAt')).toBeDefined();
expect(req.user.get('updatedAt')).toBeDefined();
expect(req.master).toBeDefined();
return false;
},
};
await reconfigureServer({
appName: 'emailVerifyToken',
verifyUserEmails: true,
emailAdapter: emailAdapter,
emailVerifyTokenValidityDuration: 5,
publicServerURL: 'http://localhost:8378/1',
sendUserEmailVerification: sendVerificationEmail.method,
});
const user = new Parse.User();
user.setPassword('password');
user.setUsername('new@example.com');
user.setEmail('user@example.com');
await user.save(null, { useMasterKey: true });
// Update email and username
user.setUsername('new@example.com');
user.setEmail('new@example.com');
await user.save(null, { useMasterKey: true });
});
it('beforeSave options do not change existing behaviour', async () => {
let sendEmailOptions;
const emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
await reconfigureServer({
appName: 'emailVerifyToken',
verifyUserEmails: true,
emailAdapter: emailAdapter,
emailVerifyTokenValidityDuration: 5, // 5 seconds
publicServerURL: 'http://localhost:8378/1',
});
const emailSpy = spyOn(emailAdapter, 'sendVerificationEmail').and.callThrough();
const newUser = new Parse.User();
newUser.setUsername('unsets_email_verify_token_expires_at');
newUser.setPassword('expiringToken');
newUser.set('email', 'user@parse.com');
await newUser.signUp();
await jasmine.timeout();
const response = await request({
url: sendEmailOptions.link,
followRedirects: false,
});
expect(response.status).toEqual(302);
const config = Config.get('test');
const results = await config.database.find('_User', {
username: 'unsets_email_verify_token_expires_at',
});
expect(results.length).toBe(1);
const user = results[0];
expect(typeof user).toBe('object');
expect(user.emailVerified).toEqual(true);
expect(typeof user._email_verify_token).toBe('undefined');
expect(typeof user._email_verify_token_expires_at).toBe('undefined');
expect(emailSpy).toHaveBeenCalled();
});
it('unsets the _email_verify_token_expires_at and _email_verify_token fields in the User class if email verification is successful', done => {
const user = new Parse.User();
let sendEmailOptions;
@@ -305,6 +532,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
request({
url: sendEmailOptions.link,
@@ -364,6 +592,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
return request({
url: sendEmailOptions.link,
@@ -499,7 +728,12 @@ describe('Email Verification Token Expiration: ', () => {
.then(() => {
const config = Config.get('test');
return config.database
.find('_User', { username: 'newEmailVerifyTokenOnEmailReset' })
.find(
'_User',
{ username: 'newEmailVerifyTokenOnEmailReset' },
{},
Auth.maintenance(config)
)
.then(results => {
return results[0];
});
@@ -576,13 +810,16 @@ describe('Email Verification Token Expiration: ', () => {
})
.then(response => {
expect(response.status).toBe(200);
})
.then(() => jasmine.timeout())
.then(() => {
expect(sendVerificationEmailCallCount).toBe(2);
expect(sendEmailOptions).toBeDefined();
// query for this user again
const config = Config.get('test');
return config.database
.find('_User', { username: 'resends_verification_token' })
.find('_User', { username: 'resends_verification_token' }, {}, Auth.maintenance(config))
.then(results => {
return results[0];
});
@@ -599,11 +836,47 @@ describe('Email Verification Token Expiration: ', () => {
done();
})
.catch(error => {
console.log(error);
jfail(error);
done();
});
});
it('provides function arguments in verifyUserEmails on verificationEmailRequest', async () => {
const user = new Parse.User();
user.setUsername('user');
user.setPassword('pass');
user.set('email', 'test@example.com');
await user.signUp();
const verifyUserEmails = {
method: async (params) => {
expect(params.object).toBeInstanceOf(Parse.User);
expect(params.ip).toBeDefined();
expect(params.master).toBeDefined();
expect(params.installationId).toBeDefined();
expect(params.resendRequest).toBeTrue();
return true;
},
};
const verifyUserEmailsSpy = spyOn(verifyUserEmails, 'method').and.callThrough();
await reconfigureServer({
appName: 'test',
publicServerURL: 'http://localhost:1337/1',
verifyUserEmails: verifyUserEmails.method,
preventLoginWithUnverifiedEmail: verifyUserEmails.method,
preventSignupWithUnverifiedEmail: true,
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
});
await expectAsync(Parse.User.requestEmailVerification('test@example.com')).toBeResolved();
expect(verifyUserEmailsSpy).toHaveBeenCalledTimes(1);
});
it('should throw with invalid emailVerifyTokenReuseIfValid', async done => {
const sendEmailOptions = [];
const emailAdapter = {
@@ -671,7 +944,7 @@ describe('Email Verification Token Expiration: ', () => {
const config = Config.get('test');
const [userBeforeRequest] = await config.database.find('_User', {
username: 'resends_verification_token',
});
}, {}, Auth.maintenance(config));
// store this user before we make our email request
expect(sendVerificationEmailCallCount).toBe(1);
await new Promise(resolve => {
@@ -691,20 +964,21 @@ describe('Email Verification Token Expiration: ', () => {
'Content-Type': 'application/json',
},
});
await jasmine.timeout();
expect(response.status).toBe(200);
expect(sendVerificationEmailCallCount).toBe(2);
expect(sendEmailOptions).toBeDefined();
const [userAfterRequest] = await config.database.find('_User', {
username: 'resends_verification_token',
});
}, {}, Auth.maintenance(config));
// verify that our token & expiration has been changed for this new request
// Verify that token & expiration haven't been changed for this new request
expect(typeof userAfterRequest).toBe('object');
expect(userBeforeRequest._email_verify_token).toBeDefined();
expect(userBeforeRequest._email_verify_token).toEqual(userAfterRequest._email_verify_token);
expect(userBeforeRequest._email_verify_token_expires_at).toEqual(
userAfterRequest._email_verify_token_expires_at
);
expect(userBeforeRequest._email_verify_token_expires_at).toBeDefined();
expect(userBeforeRequest._email_verify_token_expires_at).toEqual(userAfterRequest._email_verify_token_expires_at);
done();
});
@@ -733,6 +1007,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
return request({
url: sendEmailOptions.link,
@@ -971,6 +1246,7 @@ describe('Email Verification Token Expiration: ', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
request({
url: sendEmailOptions.link,
+2
View File
@@ -55,6 +55,8 @@ describe('FilesController', () => {
const config = Config.get(Parse.applicationId);
expect(config.database.adapter._mongoOptions.retryWrites).toBeTrue();
expect(config.filesController.adapter._mongoOptions.retryWrites).toBeTrue();
expect(config.filesController.adapter._mongoOptions.enableSchemaHooks).toBeUndefined();
expect(config.filesController.adapter._mongoOptions.schemaCacheTtl).toBeUndefined();
});
it('should create a server log on failure', done => {
+17 -1
View File
@@ -20,6 +20,22 @@ describe_only_db('mongo')('GridFSBucket', () => {
await db.dropDatabase();
});
it('should connect to mongo with the supported database options', async () => {
const databaseURI = 'mongodb://localhost:27017/parse';
const gfsAdapter = new GridFSBucketAdapter(databaseURI, {
retryWrites: true,
// these are not supported by the mongo client
enableSchemaHooks: true,
schemaCacheTtl: 5000,
maxTimeMS: 30000,
});
const db = await gfsAdapter._connect();
const status = await db.admin().serverStatus();
expect(status.connections.current > 0).toEqual(true);
expect(db.options?.retryWrites).toEqual(true);
});
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(
@@ -438,7 +454,7 @@ describe_only_db('mongo')('GridFSBucket', () => {
await db.admin().serverStatus();
expect(false).toBe(true);
} catch (e) {
expect(e.message).toEqual('MongoClient must be connected to perform this operation');
expect(e.message).toEqual('Client must be connected before running operations');
}
});
});
+2 -2
View File
@@ -1,7 +1,7 @@
'use strict';
const httpRequest = require('../lib/cloud-code/httpRequest'),
HTTPResponse = require('../lib/cloud-code/HTTPResponse').default,
const httpRequest = require('../lib/request'),
HTTPResponse = require('../lib/request').HTTPResponse,
bodyParser = require('body-parser'),
express = require('express');
+192 -154
View File
@@ -1,11 +1,19 @@
const middlewares = require('../lib/middlewares');
const AppCache = require('../lib/cache').AppCache;
const { BlockList } = require('net');
const AppCachePut = (appId, config) =>
AppCache.put(appId, {
...config,
maintenanceKeyIpsStore: new Map(),
masterKeyIpsStore: new Map(),
});
describe('middlewares', () => {
let fakeReq, fakeRes;
beforeEach(() => {
fakeReq = {
ip: '127.0.0.1',
originalUrl: 'http://example.com/parse/',
url: 'http://example.com/',
body: {
@@ -17,7 +25,7 @@ describe('middlewares', () => {
},
};
fakeRes = jasmine.createSpyObj('fakeRes', ['end', 'status']);
AppCache.put(fakeReq.body._ApplicationId, {});
AppCachePut(fakeReq.body._ApplicationId, {});
});
afterEach(() => {
@@ -25,6 +33,9 @@ describe('middlewares', () => {
});
it('should use _ContentType if provided', done => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKeyIps: ['127.0.0.1'],
});
expect(fakeReq.headers['content-type']).toEqual(undefined);
const contentType = 'image/jpeg';
fakeReq.body._ContentType = contentType;
@@ -36,7 +47,7 @@ describe('middlewares', () => {
});
it('should give invalid response when keys are configured but no key supplied', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
});
@@ -45,7 +56,7 @@ describe('middlewares', () => {
});
it('should give invalid response when keys are configured but supplied key is incorrect', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
});
@@ -55,7 +66,7 @@ describe('middlewares', () => {
});
it('should give invalid response when keys are configured but different key is supplied', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
});
@@ -65,7 +76,7 @@ describe('middlewares', () => {
});
it('should succeed when any one of the configured keys supplied', done => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
clientKey: 'clientKey',
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
@@ -78,7 +89,7 @@ describe('middlewares', () => {
});
it('should succeed when client key supplied but empty', done => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
clientKey: '',
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
@@ -91,7 +102,7 @@ describe('middlewares', () => {
});
it('should succeed when no keys are configured and none supplied', done => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
});
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
@@ -117,10 +128,12 @@ describe('middlewares', () => {
const otherKeys = BodyKeys.filter(
otherKey => otherKey !== infoKey && otherKey !== 'javascriptKey'
);
it(`it should pull ${bodyKey} into req.info`, done => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKeyIps: ['0.0.0.0/0'],
});
fakeReq.ip = '127.0.0.1';
fakeReq.body[bodyKey] = keyValue;
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeReq.body[bodyKey]).toEqual(undefined);
expect(fakeReq.info[infoKey]).toEqual(keyValue);
@@ -134,161 +147,81 @@ describe('middlewares', () => {
});
});
it('should not succeed if the ip does not belong to masterKeyIps list', () => {
AppCache.put(fakeReq.body._ApplicationId, {
it('should not succeed and log if the ip does not belong to masterKeyIps list', async () => {
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
masterKeyIps: ['10.0.0.1'],
});
fakeReq.ip = 'ip3';
fakeReq.ip = '127.0.0.1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
let error;
try {
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
} catch (err) {
error = err;
}
expect(error).toBeDefined();
expect(error.message).toEqual(`unauthorized`);
expect(logger.error).toHaveBeenCalledWith(
`Request using master key rejected as the request IP address '127.0.0.1' is not set in Parse Server option 'masterKeyIps'.`
);
});
it('should succeed if the ip does belong to masterKeyIps list', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
});
fakeReq.ip = 'ip1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
it('should not succeed and log if the ip does not belong to maintenanceKeyIps list', async () => {
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
AppCachePut(fakeReq.body._ApplicationId, {
maintenanceKey: 'masterKey',
maintenanceKeyIps: ['10.0.0.0', '10.0.0.1'],
});
fakeReq.ip = '10.0.0.2';
fakeReq.headers['x-parse-maintenance-key'] = 'masterKey';
let error;
try {
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
} catch (err) {
error = err;
}
expect(error).toBeDefined();
expect(error.message).toEqual(`unauthorized`);
expect(logger.error).toHaveBeenCalledWith(
`Request using maintenance key rejected as the request IP address '10.0.0.2' is not set in Parse Server option 'maintenanceKeyIps'.`
);
});
it('should not succeed if the connection.remoteAddress does not belong to masterKeyIps list', () => {
AppCache.put(fakeReq.body._ApplicationId, {
it('should succeed if the ip does belong to masterKeyIps list', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
masterKeyIps: ['10.0.0.1'],
});
fakeReq.connection = { remoteAddress: 'ip3' };
fakeReq.ip = '10.0.0.1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
expect(fakeReq.auth.isMaster).toBe(true);
});
it('should succeed if the connection.remoteAddress does belong to masterKeyIps list', done => {
AppCache.put(fakeReq.body._ApplicationId, {
it('should allow any ip to use masterKey if masterKeyIps is empty', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
masterKeyIps: ['0.0.0.0/0'],
});
fakeReq.connection = { remoteAddress: 'ip1' };
fakeReq.ip = '10.0.0.1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
expect(fakeReq.auth.isMaster).toBe(true);
});
it('should not succeed if the socket.remoteAddress does not belong to masterKeyIps list', () => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
});
fakeReq.socket = { remoteAddress: 'ip3' };
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
it('should succeed if the socket.remoteAddress does belong to masterKeyIps list', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
});
fakeReq.socket = { remoteAddress: 'ip1' };
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
});
it('should not succeed if the connection.socket.remoteAddress does not belong to masterKeyIps list', () => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
});
fakeReq.connection = { socket: { remoteAddress: 'ip3' } };
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
it('should succeed if the connection.socket.remoteAddress does belong to masterKeyIps list', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1', 'ip2'],
});
fakeReq.connection = { socket: { remoteAddress: 'ip1' } };
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
});
it('should allow any ip to use masterKey if masterKeyIps is empty', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: [],
});
fakeReq.ip = 'ip1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
});
it('should succeed if xff header does belong to masterKeyIps', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1'],
});
fakeReq.headers['x-parse-master-key'] = 'masterKey';
fakeReq.headers['x-forwarded-for'] = 'ip1, ip2, ip3';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
});
it('should succeed if xff header with one ip does belong to masterKeyIps', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1'],
});
fakeReq.headers['x-parse-master-key'] = 'masterKey';
fakeReq.headers['x-forwarded-for'] = 'ip1';
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
expect(fakeRes.status).not.toHaveBeenCalled();
done();
});
});
it('should not succeed if xff header does not belong to masterKeyIps', () => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip4'],
});
fakeReq.headers['x-parse-master-key'] = 'masterKey';
fakeReq.headers['x-forwarded-for'] = 'ip1, ip2, ip3';
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
it('should not succeed if xff header is empty and masterKeyIps is set', () => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['ip1'],
});
fakeReq.headers['x-parse-master-key'] = 'masterKey';
fakeReq.headers['x-forwarded-for'] = '';
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
it('can set trust proxy', async () => {
const server = await reconfigureServer({ trustProxy: 1 });
expect(server.app.parent.settings['trust proxy']).toBe(1);
});
it('should properly expose the headers', () => {
@@ -307,7 +240,7 @@ describe('middlewares', () => {
});
it('should set default Access-Control-Allow-Headers if allowHeaders are empty', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
allowHeaders: undefined,
});
const headers = {};
@@ -320,7 +253,7 @@ describe('middlewares', () => {
allowCrossDomain(fakeReq, res, () => {});
expect(headers['Access-Control-Allow-Headers']).toContain(middlewares.DEFAULT_ALLOWED_HEADERS);
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
allowHeaders: [],
});
allowCrossDomain(fakeReq, res, () => {});
@@ -328,7 +261,7 @@ describe('middlewares', () => {
});
it('should append custom headers to Access-Control-Allow-Headers if allowHeaders provided', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
allowHeaders: ['Header-1', 'Header-2'],
});
const headers = {};
@@ -344,7 +277,7 @@ describe('middlewares', () => {
});
it('should set default Access-Control-Allow-Origin if allowOrigin is empty', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
allowOrigin: undefined,
});
const headers = {};
@@ -359,7 +292,7 @@ describe('middlewares', () => {
});
it('should set custom origin to Access-Control-Allow-Origin if allowOrigin is provided', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
allowOrigin: 'https://parseplatform.org/',
});
const headers = {};
@@ -373,8 +306,37 @@ describe('middlewares', () => {
expect(headers['Access-Control-Allow-Origin']).toEqual('https://parseplatform.org/');
});
it('should use user provided on field userFromJWT', done => {
it('should support multiple origins if several are defined in allowOrigin as an array', () => {
AppCache.put(fakeReq.body._ApplicationId, {
allowOrigin: ['https://a.com', 'https://b.com', 'https://c.com'],
});
const headers = {};
const res = {
header: (key, value) => {
headers[key] = value;
},
};
const allowCrossDomain = middlewares.allowCrossDomain(fakeReq.body._ApplicationId);
// Test with the first domain
fakeReq.headers.origin = 'https://a.com';
allowCrossDomain(fakeReq, res, () => {});
expect(headers['Access-Control-Allow-Origin']).toEqual('https://a.com');
// Test with the second domain
fakeReq.headers.origin = 'https://b.com';
allowCrossDomain(fakeReq, res, () => {});
expect(headers['Access-Control-Allow-Origin']).toEqual('https://b.com');
// Test with the third domain
fakeReq.headers.origin = 'https://c.com';
allowCrossDomain(fakeReq, res, () => {});
expect(headers['Access-Control-Allow-Origin']).toEqual('https://c.com');
// Test with an unauthorized domain
fakeReq.headers.origin = 'https://unauthorized.com';
allowCrossDomain(fakeReq, res, () => {});
expect(headers['Access-Control-Allow-Origin']).toEqual('https://a.com');
});
it('should use user provided on field userFromJWT', done => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
});
fakeReq.userFromJWT = 'fake-user';
@@ -385,11 +347,87 @@ describe('middlewares', () => {
});
it('should give invalid response when upload file without x-parse-application-id in header', () => {
AppCache.put(fakeReq.body._ApplicationId, {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
});
fakeReq.body = Buffer.from('fake-file');
middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
it('should match address', () => {
const ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334';
const anotherIpv6 = '::ffff:101.10.0.1';
const ipv4 = '192.168.0.101';
const localhostV6 = '::1';
const localhostV62 = '::ffff:127.0.0.1';
const localhostV4 = '127.0.0.1';
const v6 = [ipv6, anotherIpv6];
v6.forEach(ip => {
expect(middlewares.checkIp(ip, ['::/0'], new Map())).toBe(true);
expect(middlewares.checkIp(ip, ['::'], new Map())).toBe(true);
expect(middlewares.checkIp(ip, ['0.0.0.0'], new Map())).toBe(false);
expect(middlewares.checkIp(ip, ['0.0.0.0/0'], new Map())).toBe(false);
expect(middlewares.checkIp(ip, ['123.123.123.123'], new Map())).toBe(false);
});
expect(middlewares.checkIp(ipv6, [anotherIpv6], new Map())).toBe(false);
expect(middlewares.checkIp(ipv6, [ipv6], new Map())).toBe(true);
expect(middlewares.checkIp(ipv6, ['2001:db8:85a3:0:0:8a2e:0:0/100'], new Map())).toBe(true);
expect(middlewares.checkIp(ipv4, ['::'], new Map())).toBe(false);
expect(middlewares.checkIp(ipv4, ['::/0'], new Map())).toBe(false);
expect(middlewares.checkIp(ipv4, ['0.0.0.0'], new Map())).toBe(true);
expect(middlewares.checkIp(ipv4, ['0.0.0.0/0'], new Map())).toBe(true);
expect(middlewares.checkIp(ipv4, ['123.123.123.123'], new Map())).toBe(false);
expect(middlewares.checkIp(ipv4, [ipv4], new Map())).toBe(true);
expect(middlewares.checkIp(ipv4, ['192.168.0.0/24'], new Map())).toBe(true);
expect(middlewares.checkIp(localhostV4, ['::1'], new Map())).toBe(false);
expect(middlewares.checkIp(localhostV6, ['::1'], new Map())).toBe(true);
// ::ffff:127.0.0.1 is a padded ipv4 address but not ::1
expect(middlewares.checkIp(localhostV62, ['::1'], new Map())).toBe(false);
// ::ffff:127.0.0.1 is a padded ipv4 address and is a match for 127.0.0.1
expect(middlewares.checkIp(localhostV62, ['127.0.0.1'], new Map())).toBe(true);
});
it('should match address with cache', () => {
const ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334';
const cache1 = new Map();
const spyBlockListCheck = spyOn(BlockList.prototype, 'check').and.callThrough();
expect(middlewares.checkIp(ipv6, ['::'], cache1)).toBe(true);
expect(cache1.get('2001:0db8:85a3:0000:0000:8a2e:0370:7334')).toBe(undefined);
expect(cache1.get('allowAllIpv6')).toBe(true);
expect(spyBlockListCheck).toHaveBeenCalledTimes(0);
const cache2 = new Map();
expect(middlewares.checkIp('::1', ['::1'], cache2)).toBe(true);
expect(cache2.get('::1')).toBe(true);
expect(spyBlockListCheck).toHaveBeenCalledTimes(1);
expect(middlewares.checkIp('::1', ['::1'], cache2)).toBe(true);
expect(spyBlockListCheck).toHaveBeenCalledTimes(1);
spyBlockListCheck.calls.reset();
const cache3 = new Map();
expect(middlewares.checkIp('127.0.0.1', ['127.0.0.1'], cache3)).toBe(true);
expect(cache3.get('127.0.0.1')).toBe(true);
expect(spyBlockListCheck).toHaveBeenCalledTimes(1);
expect(middlewares.checkIp('127.0.0.1', ['127.0.0.1'], cache3)).toBe(true);
expect(spyBlockListCheck).toHaveBeenCalledTimes(1);
spyBlockListCheck.calls.reset();
const cache4 = new Map();
const ranges = ['127.0.0.1', '192.168.0.0/24'];
// should not cache negative match
expect(middlewares.checkIp('123.123.123.123', ranges, cache4)).toBe(false);
expect(cache4.get('123.123.123.123')).toBe(undefined);
expect(spyBlockListCheck).toHaveBeenCalledTimes(1);
spyBlockListCheck.calls.reset();
// should not cache cidr
expect(middlewares.checkIp('192.168.0.101', ranges, cache4)).toBe(true);
expect(cache4.get('192.168.0.101')).toBe(undefined);
expect(spyBlockListCheck).toHaveBeenCalledTimes(1);
});
});
+87 -9
View File
@@ -6,7 +6,6 @@ const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDataba
const request = require('../lib/request');
const Config = require('../lib/Config');
const TestUtils = require('../lib/TestUtils');
const semver = require('semver');
const fakeClient = {
s: { options: { dbName: null } },
@@ -213,6 +212,89 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
});
it('handles nested dates', async () => {
await new Parse.Object('MyClass', {
foo: {
test: {
date: new Date(),
},
},
bar: {
date: new Date(),
},
date: new Date(),
}).save();
const adapter = Config.get(Parse.applicationId).database.adapter;
const [object] = await adapter._rawFind('MyClass', {});
expect(object.date instanceof Date).toBeTrue();
expect(object.bar.date instanceof Date).toBeTrue();
expect(object.foo.test.date instanceof Date).toBeTrue();
});
it('handles nested dates in array ', async () => {
await new Parse.Object('MyClass', {
foo: {
test: {
date: [new Date()],
},
},
bar: {
date: [new Date()],
},
date: [new Date()],
}).save();
const adapter = Config.get(Parse.applicationId).database.adapter;
const [object] = await adapter._rawFind('MyClass', {});
expect(object.date[0] instanceof Date).toBeTrue();
expect(object.bar.date[0] instanceof Date).toBeTrue();
expect(object.foo.test.date[0] instanceof Date).toBeTrue();
const obj = await new Parse.Query('MyClass').first({ useMasterKey: true });
expect(obj.get('date')[0] instanceof Date).toBeTrue();
expect(obj.get('bar').date[0] instanceof Date).toBeTrue();
expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue();
});
it('upserts with $setOnInsert', async () => {
const uuid = require('uuid');
const uuid1 = uuid.v4();
const uuid2 = uuid.v4();
const schema = {
className: 'MyClass',
fields: {
x: { type: 'Number' },
count: { type: 'Number' },
},
classLevelPermissions: {},
};
const myClassSchema = new Parse.Schema(schema.className);
myClassSchema.setCLP(schema.classLevelPermissions);
await myClassSchema.save();
const query = {
x: 1,
};
const update = {
objectId: {
__op: 'SetOnInsert',
amount: uuid1,
},
count: {
__op: 'Increment',
amount: 1,
},
};
await Parse.Server.database.update('MyClass', query, update, { upsert: true });
update.objectId.amount = uuid2;
await Parse.Server.database.update('MyClass', query, update, { upsert: true });
const res = await Parse.Server.database.find(schema.className, {}, {});
expect(res.length).toBe(1);
expect(res[0].objectId).toBe(uuid1);
expect(res[0].count).toBe(2);
expect(res[0].x).toBe(1);
});
it('handles updating a single object with array, object date', done => {
const adapter = new MongoStorageAdapter({ uri: databaseURI });
@@ -283,7 +365,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await adapter.database.admin().serverStatus();
expect(false).toBe(true);
} catch (e) {
expect(e.message).toEqual('MongoClient must be connected to perform this operation');
expect(e.message).toEqual('Client must be connected before running operations');
}
});
@@ -308,7 +390,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await expectAsync(adapter.getClass('UnknownClass')).toBeRejectedWith(undefined);
});
it_only_mongodb_version('<5.1')('should use index for caseInsensitive query', async () => {
it_only_mongodb_version('<5.1>=6')('should use index for caseInsensitive query', async () => {
const user = new Parse.User();
user.set('username', 'Bugs');
user.set('password', 'Bunny');
@@ -342,7 +424,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
expect(postIndexPlan.executionStats.executionStages.stage).toBe('FETCH');
});
it_only_mongodb_version('>=5.1')('should use index for caseInsensitive query', async () => {
it_only_mongodb_version('>=5.1<6')('should use index for caseInsensitive query', async () => {
const user = new Parse.User();
user.set('username', 'Bugs');
user.set('password', 'Bunny');
@@ -401,11 +483,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
expect(schemaAfterDeletion.fields.test).toBeUndefined();
});
if (
semver.satisfies(process.env.MONGODB_VERSION, '>=4.0.4') &&
process.env.MONGODB_TOPOLOGY === 'replicaset' &&
process.env.MONGODB_STORAGE_ENGINE === 'wiredTiger'
) {
if (process.env.MONGODB_TOPOLOGY === 'replicaset') {
describe('transactions', () => {
const headers = {
'Content-Type': 'application/json',
+2 -2
View File
@@ -87,7 +87,7 @@ describe('OAuth', function () {
done();
}
it('GET request for a resource that requires OAuth should fail with invalid credentials', done => {
xit('GET request for a resource that requires OAuth should fail with invalid credentials', done => {
/*
This endpoint has been chosen to make a request to an endpoint that requires OAuth which fails due to missing authentication.
Any other endpoint from the Twitter API that requires OAuth can be used instead in case the currently used endpoint deprecates.
@@ -105,7 +105,7 @@ describe('OAuth', function () {
});
});
it('POST request for a resource that requires OAuth should fail with invalid credentials', done => {
xit('POST request for a resource that requires OAuth should fail with invalid credentials', done => {
/*
This endpoint has been chosen to make a request to an endpoint that requires OAuth which fails due to missing authentication.
Any other endpoint from the Twitter API that requires OAuth can be used instead in case the currently used endpoint deprecates.
+6 -1
View File
@@ -749,6 +749,7 @@ describe('Pages Router', () => {
user.setPassword('examplePassword');
user.set('email', 'mail@example.com');
await user.signUp();
await jasmine.timeout();
const link = sendVerificationEmail.calls.all()[0].args[0].link;
const linkWithLocale = new URL(link);
@@ -777,6 +778,7 @@ describe('Pages Router', () => {
user.setPassword('examplePassword');
user.set('email', 'mail@example.com');
await user.signUp();
await jasmine.timeout();
const link = sendVerificationEmail.calls.all()[0].args[0].link;
const linkWithLocale = new URL(link);
@@ -830,6 +832,7 @@ describe('Pages Router', () => {
user.setPassword('examplePassword');
user.set('email', 'mail@example.com');
await user.signUp();
await jasmine.timeout();
const link = sendVerificationEmail.calls.all()[0].args[0].link;
const linkWithLocale = new URL(link);
@@ -846,6 +849,8 @@ describe('Pages Router', () => {
const locale = linkResponse.headers['x-parse-page-param-locale'];
const username = linkResponse.headers['x-parse-page-param-username'];
const publicServerUrl = linkResponse.headers['x-parse-page-param-publicserverurl'];
await jasmine.timeout();
const invalidVerificationPagePath = pageResponse.calls.all()[0].args[0];
expect(appId).toBeDefined();
expect(locale).toBe(exampleLocale);
@@ -1190,6 +1195,7 @@ describe('Pages Router', () => {
user.setPassword('examplePassword');
user.set('email', 'mail@example.com');
await user.signUp();
await jasmine.timeout();
const link = sendVerificationEmail.calls.all()[0].args[0].link;
const linkResponse = await request({
@@ -1197,7 +1203,6 @@ describe('Pages Router', () => {
followRedirects: false,
});
expect(linkResponse.status).toBe(200);
const pagePath = pageResponse.calls.all()[0].args[0];
expect(pagePath).toMatch(new RegExp(`\/${pages.emailVerificationSuccess.defaultFile}`));
});
+1 -3
View File
@@ -2,14 +2,12 @@
const request = require('../lib/request');
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const pushCompleted = async pushId => {
const query = new Parse.Query('_PushStatus');
query.equalTo('objectId', pushId);
let result = await query.first({ useMasterKey: true });
while (!(result && result.get('status') === 'succeeded')) {
await sleep(100);
await jasmine.timeout();
result = await query.first({ useMasterKey: true });
}
};
+166 -49
View File
@@ -951,57 +951,154 @@ describe('miscellaneous', function () {
);
});
it('should return the updated fields on PUT', done => {
it('return the updated fields on PUT', async () => {
const obj = new Parse.Object('GameScore');
obj
.save({ a: 'hello', c: 1, d: ['1'], e: ['1'], f: ['1', '2'] })
.then(() => {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Installation-Id': 'yolo',
};
request({
method: 'PUT',
headers: headers,
url: 'http://localhost:8378/1/classes/GameScore/' + obj.id,
body: JSON.stringify({
a: 'b',
c: { __op: 'Increment', amount: 2 },
d: { __op: 'Add', objects: ['2'] },
e: { __op: 'AddUnique', objects: ['1', '2'] },
f: { __op: 'Remove', objects: ['2'] },
selfThing: {
__type: 'Pointer',
className: 'GameScore',
objectId: obj.id,
},
}),
}).then(response => {
try {
const body = response.data;
expect(body.a).toBeUndefined();
expect(body.c).toEqual(3); // 2+1
expect(body.d.length).toBe(2);
expect(body.d.indexOf('1') > -1).toBe(true);
expect(body.d.indexOf('2') > -1).toBe(true);
expect(body.e.length).toBe(2);
expect(body.e.indexOf('1') > -1).toBe(true);
expect(body.e.indexOf('2') > -1).toBe(true);
expect(body.f.length).toBe(1);
expect(body.f.indexOf('1') > -1).toBe(true);
// return nothing on other self
expect(body.selfThing).toBeUndefined();
// updatedAt is always set
expect(body.updatedAt).not.toBeUndefined();
} catch (e) {
fail(e);
}
done();
});
const pointer = new Parse.Object('Child');
await pointer.save();
obj.set(
'point',
new Parse.GeoPoint({
latitude: 37.4848,
longitude: -122.1483,
})
.catch(done.fail);
);
obj.set('array', ['obj1', 'obj2']);
obj.set('objects', { a: 'b' });
obj.set('string', 'abc');
obj.set('bool', true);
obj.set('number', 1);
obj.set('date', new Date());
obj.set('pointer', pointer);
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Installation-Id': 'yolo',
};
const saveResponse = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/classes/GameScore',
body: JSON.stringify({
a: 'hello',
c: 1,
d: ['1'],
e: ['1'],
f: ['1', '2'],
...obj.toJSON(),
}),
});
expect(Object.keys(saveResponse.data).sort()).toEqual(['createdAt', 'objectId']);
obj.id = saveResponse.data.objectId;
const response = await request({
method: 'PUT',
headers: headers,
url: 'http://localhost:8378/1/classes/GameScore/' + obj.id,
body: JSON.stringify({
a: 'b',
c: { __op: 'Increment', amount: 2 },
d: { __op: 'Add', objects: ['2'] },
e: { __op: 'AddUnique', objects: ['1', '2'] },
f: { __op: 'Remove', objects: ['2'] },
selfThing: {
__type: 'Pointer',
className: 'GameScore',
objectId: obj.id,
},
}),
});
const body = response.data;
expect(Object.keys(body).sort()).toEqual(['c', 'd', 'e', 'f', 'updatedAt']);
expect(body.a).toBeUndefined();
expect(body.c).toEqual(3); // 2+1
expect(body.d.length).toBe(2);
expect(body.d.indexOf('1') > -1).toBe(true);
expect(body.d.indexOf('2') > -1).toBe(true);
expect(body.e.length).toBe(2);
expect(body.e.indexOf('1') > -1).toBe(true);
expect(body.e.indexOf('2') > -1).toBe(true);
expect(body.f.length).toBe(1);
expect(body.f.indexOf('1') > -1).toBe(true);
expect(body.selfThing).toBeUndefined();
expect(body.updatedAt).not.toBeUndefined();
});
it('should response should not change with triggers', async () => {
const obj = new Parse.Object('GameScore');
const pointer = new Parse.Object('Child');
Parse.Cloud.beforeSave('GameScore', request => {
return request.object;
});
Parse.Cloud.afterSave('GameScore', request => {
return request.object;
});
await pointer.save();
obj.set(
'point',
new Parse.GeoPoint({
latitude: 37.4848,
longitude: -122.1483,
})
);
obj.set('array', ['obj1', 'obj2']);
obj.set('objects', { a: 'b' });
obj.set('string', 'abc');
obj.set('bool', true);
obj.set('number', 1);
obj.set('date', new Date());
obj.set('pointer', pointer);
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Installation-Id': 'yolo',
};
const saveResponse = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/classes/GameScore',
body: JSON.stringify({
a: 'hello',
c: 1,
d: ['1'],
e: ['1'],
f: ['1', '2'],
...obj.toJSON(),
}),
});
expect(Object.keys(saveResponse.data).sort()).toEqual(['createdAt', 'objectId']);
obj.id = saveResponse.data.objectId;
const response = await request({
method: 'PUT',
headers: headers,
url: 'http://localhost:8378/1/classes/GameScore/' + obj.id,
body: JSON.stringify({
a: 'b',
c: { __op: 'Increment', amount: 2 },
d: { __op: 'Add', objects: ['2'] },
e: { __op: 'AddUnique', objects: ['1', '2'] },
f: { __op: 'Remove', objects: ['2'] },
selfThing: {
__type: 'Pointer',
className: 'GameScore',
objectId: obj.id,
},
}),
});
const body = response.data;
expect(Object.keys(body).sort()).toEqual(['c', 'd', 'e', 'f', 'updatedAt']);
expect(body.a).toBeUndefined();
expect(body.c).toEqual(3); // 2+1
expect(body.d.length).toBe(2);
expect(body.d.indexOf('1') > -1).toBe(true);
expect(body.d.indexOf('2') > -1).toBe(true);
expect(body.e.length).toBe(2);
expect(body.e.indexOf('1') > -1).toBe(true);
expect(body.e.indexOf('2') > -1).toBe(true);
expect(body.f.length).toBe(1);
expect(body.f.indexOf('1') > -1).toBe(true);
expect(body.selfThing).toBeUndefined();
expect(body.updatedAt).not.toBeUndefined();
});
it('test cloud function error handling', done => {
@@ -1170,6 +1267,26 @@ describe('miscellaneous', function () {
});
});
it('test cloud function query parameters with array of pointers', async () => {
await reconfigureServer({ encodeParseObjectInCloudFunction: false });
Parse.Cloud.define('echoParams', req => {
return req.params;
});
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/functions/echoParams',
body: '{"arr": [{ "__type": "Pointer", "className": "PointerTest" }]}',
});
const res = response.data.result;
expect(res.arr.length).toEqual(1);
});
it('can handle null params in cloud functions (regression test for #1742)', done => {
Parse.Cloud.define('func', request => {
expect(request.params.nullParam).toEqual(null);
+52
View File
@@ -0,0 +1,52 @@
const Config = require('../lib/Config');
const ParseServer = require('../lib/index').ParseServer;
describe('Config Keys', () => {
const tests = [
{
name: 'Invalid Root Keys',
options: { unknow: 'val', masterKeyIPs: '' },
error: 'unknow, masterKeyIPs',
},
{ name: 'Invalid Schema Keys', options: { schema: { Strict: 'val' } }, error: 'schema.Strict' },
{
name: 'Invalid Pages Keys',
options: { pages: { customUrls: { EmailVerificationSendFail: 'val' } } },
error: 'pages.customUrls.EmailVerificationSendFail',
},
{
name: 'Invalid LiveQueryServerOptions Keys',
options: { liveQueryServerOptions: { MasterKey: 'value' } },
error: 'liveQueryServerOptions.MasterKey',
},
{
name: 'Invalid RateLimit Keys - Array Item',
options: { rateLimit: [{ RequestPath: '' }, { RequestTimeWindow: '' }] },
error: 'rateLimit[0].RequestPath, rateLimit[1].RequestTimeWindow',
},
];
tests.forEach(test => {
it(test.name, async () => {
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callThrough();
spyOn(Config, 'validateOptions').and.callFake(() => {});
new ParseServer({
...defaultConfiguration,
...test.options,
});
expect(logger.error).toHaveBeenCalledWith(`Invalid Option Keys Found: ${test.error}`);
});
});
it('should run fine', async () => {
try {
await reconfigureServer({
...defaultConfiguration,
});
} catch (err) {
fail('Should run without error');
}
});
});
+530 -35
View File
@@ -37,8 +37,14 @@ describe('Parse.File testing', () => {
});
});
it('works with _ContentType', done => {
request({
it('works with _ContentType', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['*'],
},
});
let response = await request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
@@ -47,21 +53,18 @@ describe('Parse.File testing', () => {
_ContentType: 'text/html',
base64: 'PGh0bWw+PC9odG1sPgo=',
}),
}).then(response => {
const b = response.data;
expect(b.name).toMatch(/_file.html/);
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*file.html$/);
request({ url: b.url }).then(response => {
const body = response.text;
try {
expect(response.headers['content-type']).toMatch('^text/html');
expect(body).toEqual('<html></html>\n');
} catch (e) {
jfail(e);
}
done();
});
});
const b = response.data;
expect(b.name).toMatch(/_file.html/);
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*file.html$/);
response = await request({ url: b.url });
const body = response.text;
try {
expect(response.headers['content-type']).toMatch('^text/html');
expect(body).toEqual('<html></html>\n');
} catch (e) {
jfail(e);
}
});
it('works without Content-Type', done => {
@@ -351,25 +354,28 @@ describe('Parse.File testing', () => {
ok(object.toJSON().file.url);
});
it('content-type used with no extension', done => {
it('content-type used with no extension', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['*'],
},
});
const headers = {
'Content-Type': 'text/html',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
request({
let response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/files/file',
body: 'fee fi fo',
}).then(response => {
const b = response.data;
expect(b.name).toMatch(/\.html$/);
request({ url: b.url }).then(response => {
expect(response.headers['content-type']).toMatch(/^text\/html/);
done();
});
});
const b = response.data;
expect(b.name).toMatch(/\.html$/);
response = await request({ url: b.url });
expect(response.headers['content-type']).toMatch(/^text\/html/);
});
it('filename is url encoded', done => {
@@ -654,7 +660,236 @@ describe('Parse.File testing', () => {
});
});
xdescribe('Gridstore Range tests', () => {
describe('getting files', () => {
it('does not crash on file request with invalid app ID', async () => {
const res1 = await request({
url: 'http://localhost:8378/1/files/invalid-id/invalid-file.txt',
}).catch(e => e);
expect(res1.status).toBe(403);
expect(res1.data).toEqual({ code: 119, error: 'Invalid application ID.' });
// Ensure server did not crash
const res2 = await request({ url: 'http://localhost:8378/1/health' });
expect(res2.status).toEqual(200);
expect(res2.data).toEqual({ status: 'ok' });
});
it('does not crash on file request with invalid path', async () => {
const res1 = await request({
url: 'http://localhost:8378/1/files/invalid-id//invalid-path/%20/invalid-file.txt',
}).catch(e => e);
expect(res1.status).toBe(403);
expect(res1.data).toEqual({ error: 'unauthorized' });
// Ensure server did not crash
const res2 = await request({ url: 'http://localhost:8378/1/health' });
expect(res2.status).toEqual(200);
expect(res2.data).toEqual({ status: 'ok' });
});
it('does not crash on file metadata request with invalid app ID', async () => {
const res1 = await request({
url: `http://localhost:8378/1/files/invalid-id/metadata/invalid-file.txt`,
});
expect(res1.status).toBe(200);
expect(res1.data).toEqual({});
// Ensure server did not crash
const res2 = await request({ url: 'http://localhost:8378/1/health' });
expect(res2.status).toEqual(200);
expect(res2.data).toEqual({ status: 'ok' });
});
});
describe_only_db('mongo')('Gridstore Range', () => {
it('supports bytes range out of range', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=15000-18000',
},
});
expect(file.headers['content-range']).toBe('bytes 1212-1212/1212');
});
it('supports bytes range if end greater than start', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=15000-100',
},
});
expect(file.headers['content-range']).toBe('bytes 100-1212/1212');
});
it('supports bytes range if end is undefined', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=100-',
},
});
expect(file.headers['content-range']).toBe('bytes 100-1212/1212');
});
it('supports bytes range if start and end undefined', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=abc-efs',
},
}).catch(e => e);
expect(file.headers['content-range']).toBeUndefined();
});
it('supports bytes range if start and end undefined', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
},
}).catch(e => e);
expect(file.headers['content-range']).toBeUndefined();
});
it('supports bytes range if end is greater than size', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=0-2000',
},
}).catch(e => e);
expect(file.headers['content-range']).toBe('bytes 0-1212/1212');
});
it('supports bytes range if end is greater than size', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: repeat('argle bargle', 100),
});
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=0-2000',
},
}).catch(e => e);
expect(file.headers['content-range']).toBe('bytes 0-1212/1212');
});
it('supports bytes range with 0 length', async () => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const response = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1//files/file.txt ',
body: 'a',
}).catch(e => e);
const b = response.data;
const file = await request({
url: b.url,
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
Range: 'bytes=-2000',
},
}).catch(e => e);
expect(file.headers['content-range']).toBe('bytes 0-1/1');
});
it('supports range requests', done => {
const headers = {
'Content-Type': 'application/octet-stream',
@@ -743,7 +978,7 @@ describe('Parse.File testing', () => {
});
});
xit('supports getting last n bytes', done => {
it('supports getting last n bytes', done => {
const headers = {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
@@ -841,8 +1076,8 @@ describe('Parse.File testing', () => {
});
});
it('fails to stream unknown file', done => {
request({
it('fails to stream unknown file', async () => {
const response = await request({
url: 'http://localhost:8378/1/files/test/file.txt',
headers: {
'Content-Type': 'application/octet-stream',
@@ -850,12 +1085,10 @@ describe('Parse.File testing', () => {
'X-Parse-REST-API-Key': 'rest',
Range: 'bytes=13-240',
},
}).then(response => {
expect(response.status).toBe(404);
const body = response.text;
expect(body).toEqual('File not found.');
done();
});
}).catch(e => e);
expect(response.status).toBe(404);
const body = response.text;
expect(body).toEqual('File not found.');
});
});
@@ -1071,6 +1304,268 @@ describe('Parse.File testing', () => {
await expectAsync(reconfigureServer({ fileUpload: { [key]: value } })).toBeResolved();
}
}
await expectAsync(
reconfigureServer({
fileUpload: {
fileExtensions: 1,
},
})
).toBeRejectedWith('fileUpload.fileExtensions must be an array.');
});
});
describe('fileExtensions', () => {
it('works with _ContentType', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['png'],
},
});
await expectAsync(
request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'text/html',
base64: 'PGh0bWw+PC9odG1sPgo=',
}),
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`)
);
});
it('works without Content-Type', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
await expectAsync(
request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/files/file.html',
body: '<html></html>\n',
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`)
);
});
it('default should allow common types', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
},
});
for (const type of ['plain', 'txt', 'png', 'jpg', 'gif', 'doc']) {
const file = new Parse.File(`parse-server-logo.${type}`, { base64: 'ParseA==' });
await file.save();
}
});
it('works with a period in the file name', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'],
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const values = ['file.png.html', 'file.txt.png.html', 'file.png.txt.html'];
for (const value of values) {
await expectAsync(
request({
method: 'POST',
headers: headers,
url: `http://localhost:8378/1/files/${value}`,
body: '<html></html>\n',
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`)
);
}
});
it('works to stop invalid filenames', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'],
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const values = [
'!invalid.png',
'.png',
'.html',
' .html',
'.png.html',
'~invalid.png',
'-invalid.png',
];
for (const value of values) {
await expectAsync(
request({
method: 'POST',
headers: headers,
url: `http://localhost:8378/1/files/${value}`,
body: '<html></html>\n',
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.INVALID_FILE_NAME, `Filename contains invalid characters.`)
);
}
});
it('allows file without extension', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'],
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const values = ['filenamewithoutextension'];
for (const value of values) {
await expectAsync(
request({
method: 'POST',
headers: headers,
url: `http://localhost:8378/1/files/${value}`,
body: '<html></html>\n',
}).catch(e => {
throw new Error(e.data.error);
})
).toBeResolved();
}
});
it('works with array', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['jpg', 'wav'],
},
});
await expectAsync(
request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'text/html',
base64: 'PGh0bWw+PC9odG1sPgo=',
}),
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`)
);
await expectAsync(
request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'image/jpg',
base64: 'PGh0bWw+PC9odG1sPgo=',
}),
})
).toBeResolved();
await expectAsync(
request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'audio/wav',
base64: 'UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA',
}),
})
).toBeResolved();
});
it('works with array without Content-Type', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['jpg'],
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
await expectAsync(
request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/files/file.html',
body: '<html></html>\n',
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`)
);
});
it('works with array with correct file type', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
fileExtensions: ['html'],
},
});
const response = await request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'text/html',
base64: 'PGh0bWw+PC9odG1sPgo=',
}),
});
const b = response.data;
expect(b.name).toMatch(/_file.html$/);
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*file.html$/);
});
});
});
+1 -1
View File
@@ -47,7 +47,7 @@ describe('Parse.GeoPoint testing', () => {
obj.set('location', point);
obj.set('name', 'Zhoul');
await obj.save();
Parse.Cloud.httpRequest({
request({
url: 'http://localhost:8378/1/classes/TestObject/' + obj.id,
headers: {
'X-Parse-Application-Id': 'test',
+544 -20
View File
@@ -8,7 +8,7 @@ require('./helper');
const { updateCLP } = require('./support/dev');
const pluralize = require('pluralize');
const { getMainDefinition } = require('apollo-utilities');
const { getMainDefinition } = require('@apollo/client/utilities');
const { createUploadLink } = require('apollo-upload-client');
const { SubscriptionClient } = require('subscriptions-transport-ws');
const { WebSocketLink } = require('@apollo/client/link/ws');
@@ -49,7 +49,9 @@ describe('ParseGraphQLServer', () => {
let parseGraphQLServer;
beforeEach(async () => {
parseServer = await global.reconfigureServer({});
parseServer = await global.reconfigureServer({
maxUploadSize: '1kb',
});
parseGraphQLServer = new ParseGraphQLServer(parseServer, {
graphQLPath: '/graphql',
playgroundPath: '/playground',
@@ -122,15 +124,16 @@ describe('ParseGraphQLServer', () => {
info: new Object(),
config: new Object(),
auth: new Object(),
get: () => {},
};
const res = {
set: () => {},
};
it("should return schema and context with req's info, config and auth", async () => {
const options = await parseGraphQLServer._getGraphQLOptions();
expect(options.multipart).toEqual({
fileSize: 20971520,
});
expect(options.schema).toEqual(parseGraphQLServer.parseGraphQLSchema.graphQLSchema);
const contextResponse = options.context({ req });
const contextResponse = await options.context({ req, res });
expect(contextResponse.info).toEqual(req.info);
expect(contextResponse.config).toEqual(req.config);
expect(contextResponse.auth).toEqual(req.auth);
@@ -292,30 +295,37 @@ describe('ParseGraphQLServer', () => {
let objects = [];
async function prepareData() {
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user1 = new Parse.User();
user1.setUsername('user1');
user1.setPassword('user1');
user1.setEmail('user1@user1.user1');
user1.setACL(acl);
await user1.signUp();
user2 = new Parse.User();
user2.setUsername('user2');
user2.setPassword('user2');
user2.setACL(acl);
await user2.signUp();
user3 = new Parse.User();
user3.setUsername('user3');
user3.setPassword('user3');
user3.setACL(acl);
await user3.signUp();
user4 = new Parse.User();
user4.setUsername('user4');
user4.setPassword('user4');
user4.setACL(acl);
await user4.signUp();
user5 = new Parse.User();
user5.setUsername('user5');
user5.setPassword('user5');
user5.setACL(acl);
await user5.signUp();
const roleACL = new Parse.ACL();
@@ -425,7 +435,7 @@ describe('ParseGraphQLServer', () => {
const expressApp = express();
httpServer = http.createServer(expressApp);
expressApp.use('/parse', parseServer.app);
parseLiveQueryServer = ParseServer.createLiveQueryServer(httpServer, {
parseLiveQueryServer = await ParseServer.createLiveQueryServer(httpServer, {
port: 1338,
});
parseGraphQLServer.applyGraphQL(expressApp);
@@ -942,8 +952,7 @@ describe('ParseGraphQLServer', () => {
).data['__type'].inputFields
.map(field => field.name)
.sort();
expect(inputFields).toEqual(['clientMutationId', 'password', 'username']);
expect(inputFields).toEqual(['authData', 'clientMutationId', 'password', 'username']);
});
it('should have clientMutationId in log in mutation payload', async () => {
@@ -5269,7 +5278,6 @@ describe('ParseGraphQLServer', () => {
it('should only count', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const where = {
@@ -6827,7 +6835,7 @@ describe('ParseGraphQLServer', () => {
describe('Files Mutations', () => {
describe('Create', () => {
it_only_node_version('<17')('should return File object', async () => {
it('should return File object', async () => {
const clientMutationId = uuidv4();
parseServer = await global.reconfigureServer({
@@ -7027,7 +7035,66 @@ describe('ParseGraphQLServer', () => {
});
describe('Users Mutations', () => {
const challengeAdapter = {
validateAuthData: () => Promise.resolve({ response: { someData: true } }),
validateAppId: () => Promise.resolve(),
challenge: () => Promise.resolve({ someData: true }),
options: { anOption: true },
};
it('should create user and return authData response', async () => {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
auth: {
challengeAdapter,
},
});
const clientMutationId = uuidv4();
const result = await apolloClient.mutate({
mutation: gql`
mutation createUser($input: CreateUserInput!) {
createUser(input: $input) {
clientMutationId
user {
id
authDataResponse
}
}
}
`,
variables: {
input: {
clientMutationId,
fields: {
authData: {
challengeAdapter: {
id: 'challengeAdapter',
},
},
},
},
},
context: {
headers: {
'X-Parse-Master-Key': 'test',
},
},
});
expect(result.data.createUser.clientMutationId).toEqual(clientMutationId);
expect(result.data.createUser.user.authDataResponse).toEqual({
challengeAdapter: { someData: true },
});
});
it('should sign user up', async () => {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
auth: {
challengeAdapter,
},
});
const clientMutationId = uuidv4();
const userSchema = new Parse.Schema('_User');
userSchema.addString('someField');
@@ -7044,6 +7111,7 @@ describe('ParseGraphQLServer', () => {
sessionToken
user {
someField
authDataResponse
aPointer {
id
username
@@ -7059,11 +7127,17 @@ describe('ParseGraphQLServer', () => {
fields: {
username: 'user1',
password: 'user1',
authData: {
challengeAdapter: {
id: 'challengeAdapter',
},
},
aPointer: {
createAndLink: {
username: 'user2',
password: 'user2',
someField: 'someValue2',
ACL: { public: { read: true, write: true } },
},
},
someField: 'someValue',
@@ -7078,6 +7152,9 @@ describe('ParseGraphQLServer', () => {
expect(result.data.signUp.viewer.user.aPointer.id).toBeDefined();
expect(result.data.signUp.viewer.user.aPointer.username).toEqual('user2');
expect(typeof result.data.signUp.viewer.sessionToken).toBe('string');
expect(result.data.signUp.viewer.user.authDataResponse).toEqual({
challengeAdapter: { someData: true },
});
});
it('should login with user', async () => {
@@ -7086,6 +7163,7 @@ describe('ParseGraphQLServer', () => {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
auth: {
challengeAdapter,
myAuth: {
module: global.mockCustomAuthenticator('parse', 'graphql'),
},
@@ -7105,6 +7183,7 @@ describe('ParseGraphQLServer', () => {
sessionToken
user {
someField
authDataResponse
aPointer {
id
username
@@ -7118,6 +7197,7 @@ describe('ParseGraphQLServer', () => {
input: {
clientMutationId,
authData: {
challengeAdapter: { id: 'challengeAdapter' },
myAuth: {
id: 'parse',
password: 'graphql',
@@ -7130,6 +7210,7 @@ describe('ParseGraphQLServer', () => {
username: 'user2',
password: 'user2',
someField: 'someValue2',
ACL: { public: { read: true, write: true } },
},
},
},
@@ -7143,9 +7224,92 @@ describe('ParseGraphQLServer', () => {
expect(typeof result.data.logInWith.viewer.sessionToken).toBe('string');
expect(result.data.logInWith.viewer.user.aPointer.id).toBeDefined();
expect(result.data.logInWith.viewer.user.aPointer.username).toEqual('user2');
expect(result.data.logInWith.viewer.user.authDataResponse).toEqual({
challengeAdapter: { someData: true },
});
});
it('should handle challenge', async () => {
const clientMutationId = uuidv4();
spyOn(challengeAdapter, 'challenge').and.callThrough();
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
auth: {
challengeAdapter,
},
});
const user = new Parse.User();
await user.save({ username: 'username', password: 'password' });
const result = await apolloClient.mutate({
mutation: gql`
mutation Challenge($input: ChallengeInput!) {
challenge(input: $input) {
clientMutationId
challengeData
}
}
`,
variables: {
input: {
clientMutationId,
username: 'username',
password: 'password',
challengeData: {
challengeAdapter: { someChallengeData: true },
},
},
},
});
const challengeCall = challengeAdapter.challenge.calls.argsFor(0);
expect(challengeAdapter.challenge).toHaveBeenCalledTimes(1);
expect(challengeCall[0]).toEqual({ someChallengeData: true });
expect(challengeCall[1]).toEqual(undefined);
expect(challengeCall[2]).toEqual(challengeAdapter);
expect(challengeCall[3].object instanceof Parse.User).toBeTruthy();
expect(challengeCall[3].original instanceof Parse.User).toBeTruthy();
expect(challengeCall[3].isChallenge).toBeTruthy();
expect(challengeCall[3].object.id).toEqual(user.id);
expect(challengeCall[3].original.id).toEqual(user.id);
expect(result.data.challenge.clientMutationId).toEqual(clientMutationId);
expect(result.data.challenge.challengeData).toEqual({
challengeAdapter: { someData: true },
});
await expectAsync(
apolloClient.mutate({
mutation: gql`
mutation Challenge($input: ChallengeInput!) {
challenge(input: $input) {
clientMutationId
challengeData
}
}
`,
variables: {
input: {
clientMutationId,
username: 'username',
password: 'wrongPassword',
challengeData: {
challengeAdapter: { someChallengeData: true },
},
},
},
})
).toBeRejected();
});
it('should log the user in', async () => {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
auth: {
challengeAdapter,
},
});
const clientMutationId = uuidv4();
const user = new Parse.User();
user.setUsername('user1');
@@ -7162,6 +7326,7 @@ describe('ParseGraphQLServer', () => {
viewer {
sessionToken
user {
authDataResponse
someField
}
}
@@ -7173,6 +7338,7 @@ describe('ParseGraphQLServer', () => {
clientMutationId,
username: 'user1',
password: 'user1',
authData: { challengeAdapter: { token: true } },
},
},
});
@@ -7181,6 +7347,9 @@ describe('ParseGraphQLServer', () => {
expect(result.data.logIn.viewer.sessionToken).toBeDefined();
expect(result.data.logIn.viewer.user.someField).toEqual('someValue');
expect(typeof result.data.logIn.viewer.sessionToken).toBe('string');
expect(result.data.logIn.viewer.user.authDataResponse).toEqual({
challengeAdapter: { someData: true },
});
});
it('should log the user out', async () => {
@@ -8155,19 +8324,21 @@ describe('ParseGraphQLServer', () => {
const someClass = new Parse.Object('SomeClass');
await someClass.save();
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const user = new Parse.User();
user.set('username', 'username');
user.set('password', 'password');
user.setACL(roleACL);
await user.signUp();
const user2 = new Parse.User();
user2.set('username', 'username2');
user2.set('password', 'password2');
user2.setACL(roleACL);
await user2.signUp();
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('aRole', roleACL);
await role.save();
@@ -9130,7 +9301,7 @@ describe('ParseGraphQLServer', () => {
expect(result6[0].node.name).toEqual('imACountry3');
});
it_only_node_version('<17')('should support files', async () => {
it('should support files', async () => {
try {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
@@ -9172,7 +9343,6 @@ describe('ParseGraphQLServer', () => {
expect(res.status).toEqual(200);
const result = JSON.parse(await res.text());
expect(result.data.createFile.fileInfo.name).toEqual(
jasmine.stringMatching(/_myFileName.txt$/)
);
@@ -9378,9 +9548,233 @@ describe('ParseGraphQLServer', () => {
}
});
it_only_node_version('<17')('should not upload if file is too large', async () => {
parseGraphQLServer.parseServer.config.maxUploadSize = '1kb';
it('should support files on required file', async () => {
try {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
});
const schemaController = await parseServer.config.databaseController.loadSchema();
await schemaController.addClassIfNotExists('SomeClassWithRequiredFile', {
someField: { type: 'File', required: true },
});
await resetGraphQLCache();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const body = new FormData();
body.append(
'operations',
JSON.stringify({
query: `
mutation CreateSomeObject(
$fields: CreateSomeClassWithRequiredFileFieldsInput
) {
createSomeClassWithRequiredFile(
input: { fields: $fields }
) {
someClassWithRequiredFile {
id
someField {
name
url
}
}
}
}
`,
variables: {
fields: {
someField: { upload: null },
},
},
})
);
body.append('map', JSON.stringify({ 1: ['variables.fields.someField.upload'] }));
body.append('1', 'My File Content', {
filename: 'myFileName.txt',
contentType: 'text/plain',
});
const res = await fetch('http://localhost:13377/graphql', {
method: 'POST',
headers,
body,
});
expect(res.status).toEqual(200);
const resText = await res.text();
const result = JSON.parse(resText);
expect(
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.name
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
expect(
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.url
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
} catch (e) {
handleError(e);
}
});
it('should support file upload for on fly creation through pointer and relation', async () => {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
});
const schema = new Parse.Schema('SomeClass');
schema.addFile('someFileField');
schema.addPointer('somePointerField', 'SomeClass');
schema.addRelation('someRelationField', 'SomeClass');
await schema.save();
const body = new FormData();
body.append(
'operations',
JSON.stringify({
query: `
mutation UploadFiles(
$fields: CreateSomeClassFieldsInput
) {
createSomeClass(
input: { fields: $fields }
) {
someClass {
id
someFileField {
name
url
}
somePointerField {
id
someFileField {
name
url
}
}
someRelationField {
edges {
node {
id
someFileField {
name
url
}
}
}
}
}
}
}
`,
variables: {
fields: {
someFileField: { upload: null },
somePointerField: {
createAndLink: {
someFileField: { upload: null },
},
},
someRelationField: {
createAndAdd: [
{
someFileField: { upload: null },
},
],
},
},
},
})
);
body.append(
'map',
JSON.stringify({
1: ['variables.fields.someFileField.upload'],
2: ['variables.fields.somePointerField.createAndLink.someFileField.upload'],
3: ['variables.fields.someRelationField.createAndAdd.0.someFileField.upload'],
})
);
body.append('1', 'My File Content someFileField', {
filename: 'someFileField.txt',
contentType: 'text/plain',
});
body.append('2', 'My File Content somePointerField', {
filename: 'somePointerField.txt',
contentType: 'text/plain',
});
body.append('3', 'My File Content someRelationField', {
filename: 'someRelationField.txt',
contentType: 'text/plain',
});
const res = await fetch('http://localhost:13377/graphql', {
method: 'POST',
headers,
body,
});
expect(res.status).toEqual(200);
const result = await res.json();
expect(result.data.createSomeClass.someClass.someFileField.name).toEqual(
jasmine.stringMatching(/_someFileField.txt$/)
);
expect(result.data.createSomeClass.someClass.somePointerField.someFileField.name).toEqual(
jasmine.stringMatching(/_somePointerField.txt$/)
);
expect(
result.data.createSomeClass.someClass.someRelationField.edges[0].node.someFileField.name
).toEqual(jasmine.stringMatching(/_someRelationField.txt$/));
});
it('should support files and add extension from mimetype', async () => {
try {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
});
const body = new FormData();
body.append(
'operations',
JSON.stringify({
query: `
mutation CreateFile($input: CreateFileInput!) {
createFile(input: $input) {
fileInfo {
name
url
}
}
}
`,
variables: {
input: {
upload: null,
},
},
})
);
body.append('map', JSON.stringify({ 1: ['variables.input.upload'] }));
body.append('1', 'My File Content', {
// No extension, the system should add it from mimetype
filename: 'myFileName',
contentType: 'text/plain',
});
const res = await fetch('http://localhost:13377/graphql', {
method: 'POST',
headers,
body,
});
expect(res.status).toEqual(200);
const result = JSON.parse(await res.text());
expect(result.data.createFile.fileInfo.name).toEqual(
jasmine.stringMatching(/_myFileName.txt$/)
);
expect(result.data.createFile.fileInfo.url).toEqual(
jasmine.stringMatching(/_myFileName.txt$/)
);
} catch (e) {
handleError(e);
}
});
it('should not upload if file is too large', async () => {
const body = new FormData();
body.append(
'operations',
@@ -9405,6 +9799,7 @@ describe('ParseGraphQLServer', () => {
body.append('map', JSON.stringify({ 1: ['variables.input.upload'] }));
body.append(
'1',
// In this test file parse server is setup with 1kb limit
Buffer.alloc(parseGraphQLServer._transformMaxUploadSizeToBytes('2kb'), 1),
{
filename: 'myFileName.txt',
@@ -9419,8 +9814,10 @@ describe('ParseGraphQLServer', () => {
});
const result = JSON.parse(await res.text());
expect(res.status).toEqual(500);
expect(result.errors[0].message).toEqual('File size limit exceeded: 1024 bytes');
expect(res.status).toEqual(200);
expect(result.errors[0].message).toEqual(
'File truncated as it exceeds the 1024 byte size limit.'
);
});
it('should support object values', async () => {
@@ -9516,6 +9913,130 @@ describe('ParseGraphQLServer', () => {
}
});
it('should support where argument on object field that contains false boolean value or 0 number value', async () => {
try {
const someObjectFieldValue1 = {
foo: { bar: true, baz: 100 },
};
const someObjectFieldValue2 = {
foo: { bar: false, baz: 0 },
};
const object1 = new Parse.Object('SomeClass');
await object1.save({
someObjectField: someObjectFieldValue1,
});
const object2 = new Parse.Object('SomeClass');
await object2.save({
someObjectField: someObjectFieldValue2,
});
const whereToObject1 = {
someObjectField: {
equalTo: { key: 'foo.bar', value: true },
notEqualTo: { key: 'foo.baz', value: 0 },
},
};
const whereToObject2 = {
someObjectField: {
notEqualTo: { key: 'foo.bar', value: true },
equalTo: { key: 'foo.baz', value: 0 },
},
};
const whereToAll = {
someObjectField: {
lessThan: { key: 'foo.baz', value: 101 },
},
};
const whereToNone = {
someObjectField: {
notEqualTo: { key: 'foo.bar', value: true },
equalTo: { key: 'foo.baz', value: 1 },
},
};
const queryResult = await apolloClient.query({
query: gql`
query GetSomeObject(
$id1: ID!
$id2: ID!
$whereToObject1: SomeClassWhereInput
$whereToObject2: SomeClassWhereInput
$whereToAll: SomeClassWhereInput
$whereToNone: SomeClassWhereInput
) {
obj1: someClass(id: $id1) {
id
someObjectField
}
obj2: someClass(id: $id2) {
id
someObjectField
}
onlyObj1: someClasses(where: $whereToObject1) {
edges {
node {
id
someObjectField
}
}
}
onlyObj2: someClasses(where: $whereToObject2) {
edges {
node {
id
someObjectField
}
}
}
all: someClasses(where: $whereToAll) {
edges {
node {
id
someObjectField
}
}
}
none: someClasses(where: $whereToNone) {
edges {
node {
id
someObjectField
}
}
}
}
`,
variables: {
id1: object1.id,
id2: object2.id,
whereToObject1,
whereToObject2,
whereToAll,
whereToNone,
},
});
const { obj1, obj2, onlyObj1, onlyObj2, all, none } = queryResult.data;
expect(obj1.someObjectField).toEqual(someObjectFieldValue1);
expect(obj2.someObjectField).toEqual(someObjectFieldValue2);
// Checks class query results
expect(onlyObj1.edges.length).toEqual(1);
expect(onlyObj1.edges[0].node.someObjectField).toEqual(someObjectFieldValue1);
expect(onlyObj2.edges.length).toEqual(1);
expect(onlyObj2.edges[0].node.someObjectField).toEqual(someObjectFieldValue2);
expect(all.edges.length).toEqual(2);
expect(none.edges.length).toEqual(0);
} catch (e) {
handleError(e);
}
});
it('should support object composed queries', async () => {
try {
const someObjectFieldValue1 = {
@@ -10320,6 +10841,9 @@ describe('ParseGraphQLServer', () => {
const user = new Parse.User();
user.setUsername('user1');
user.setPassword('user1');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.signUp();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
+35 -2
View File
@@ -190,7 +190,7 @@ describe('Hooks', () => {
it('should fail trying to create two times the same function', done => {
Parse.Hooks.createFunction('my_new_function', 'http://url.com')
.then(() => new Promise(resolve => setTimeout(resolve, 100)))
.then(() => jasmine.timeout())
.then(
() => {
return Parse.Hooks.createFunction('my_new_function', 'http://url.com');
@@ -208,7 +208,7 @@ describe('Hooks', () => {
expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.message).toBe('function name: my_new_function already exits');
expect(err.message).toBe('function name: my_new_function already exists');
}
return Parse.Hooks.removeFunction('my_new_function');
}
@@ -694,3 +694,36 @@ describe('triggers', () => {
expect(req.context).toBeUndefined();
});
});
describe('sanitizing names', () => {
const invalidNames = [
`test'%3bdeclare%20@q%20varchar(99)%3bset%20@q%3d'%5c%5cxxxxxxxxxxxxxxx.yyyyy'%2b'fy.com%5cxus'%3b%20exec%20master.dbo.xp_dirtree%20@q%3b--%20`,
`test.function.name`,
];
it('should not crash server and return error on invalid Cloud Function name', async () => {
for (const invalidName of invalidNames) {
let error;
try {
await Parse.Cloud.run(invalidName);
} catch (err) {
error = err;
}
expect(error).toBeDefined();
expect(error.message).toMatch(/Invalid function/);
}
});
it('should not crash server and return error on invalid Cloud Job name', async () => {
for (const invalidName of invalidNames) {
let error;
try {
await Parse.Cloud.startJob(invalidName);
} catch (err) {
error = err;
}
expect(error).toBeDefined();
expect(error.message).toMatch(/Invalid job/);
}
});
});
+50
View File
@@ -1239,6 +1239,56 @@ describe('Installations', () => {
});
});
it('can use push with beforeSave', async () => {
const input = {
deviceToken: '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306',
deviceType: 'ios',
};
await rest.create(config, auth.nobody(config), '_Installation', input);
const functions = {
beforeSave() {},
afterSave() {},
};
spyOn(functions, 'beforeSave').and.callThrough();
spyOn(functions, 'afterSave').and.callThrough();
Parse.Cloud.beforeSave(Parse.Installation, functions.beforeSave);
Parse.Cloud.afterSave(Parse.Installation, functions.afterSave);
await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
await Parse.Push.send({
where: {
deviceType: 'ios',
},
data: {
badge: 'increment',
alert: 'Hello world!',
},
});
await new Promise(resolve => setTimeout(resolve, 1000));
const installation = await new Parse.Query(Parse.Installation).first({ useMasterKey: true });
expect(installation.get('badge')).toEqual(3);
expect(functions.beforeSave).not.toHaveBeenCalled();
expect(functions.afterSave).not.toHaveBeenCalled();
});
// TODO: Look at additional tests from installation_collection_test.go:882
// TODO: Do we need to support _tombstone disabling of installations?
// TODO: Test deletion, badge increments
+298 -185
View File
@@ -1,21 +1,23 @@
'use strict';
const Auth = require('../lib/Auth');
const UserController = require('../lib/Controllers/UserController').UserController;
const Config = require('../lib/Config');
const ParseServer = require('../lib/index').ParseServer;
const triggers = require('../lib/triggers');
const { resolvingPromise, sleep } = require('./support/testUtils');
const validatorFail = () => {
throw 'you are not authorized';
};
describe('ParseLiveQuery', function () {
it('access user on onLiveQueryEvent disconnect', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
beforeEach(() => {
Parse.CoreManager.getLiveQueryController().setDefaultLiveQueryClient(null);
});
afterEach(async () => {
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
await client.close();
});
it('access user on onLiveQueryEvent disconnect', async done => {
const requestedUser = new Parse.User();
requestedUser.setUsername('username');
requestedUser.setPassword('password');
@@ -32,18 +34,10 @@ describe('ParseLiveQuery', function () {
const query = new Parse.Query(TestObject);
await query.subscribe();
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
client.close();
await client.close();
});
it('can subscribe to query', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
@@ -109,14 +103,6 @@ describe('ParseLiveQuery', function () {
});
it('expect afterEvent payload', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
@@ -136,14 +122,6 @@ describe('ParseLiveQuery', function () {
});
it('expect afterEvent enter', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('enter');
expect(req.user).toBeUndefined();
@@ -167,14 +145,6 @@ describe('ParseLiveQuery', function () {
});
it('expect afterEvent leave', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('leave');
expect(req.user).toBeUndefined();
@@ -199,14 +169,6 @@ describe('ParseLiveQuery', function () {
});
it('expect afterEvent delete', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
expect(req.event).toBe('delete');
expect(req.user).toBeUndefined();
@@ -354,30 +316,18 @@ describe('ParseLiveQuery', function () {
);
});
it('can handle afterEvent sendEvent to false', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
it('can handle afterEvent sendEvent to false', async () => {
const object = new TestObject();
await object.save();
const promise = resolvingPromise();
Parse.Cloud.afterLiveQueryEvent('TestObject', req => {
const current = req.object;
const original = req.original;
setTimeout(() => {
done();
}, 2000);
if (current.get('foo') != original.get('foo')) {
req.sendEvent = false;
}
promise.resolve();
});
const query = new Parse.Query(TestObject);
@@ -391,6 +341,50 @@ describe('ParseLiveQuery', function () {
});
object.set({ foo: 'bar' });
await object.save();
await promise;
});
it('can handle live query with fields', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['Test'],
},
startLiveQueryServer: true,
});
const query = new Parse.Query('Test');
query.watch('yolo');
const subscription = await query.subscribe();
const spy = {
create(obj) {
if (!obj.get('yolo')) {
fail('create should not have been called');
}
},
update(object, original) {
if (object.get('yolo') === original.get('yolo')) {
fail('create should not have been called');
}
},
};
const createSpy = spyOn(spy, 'create').and.callThrough();
const updateSpy = spyOn(spy, 'update').and.callThrough();
subscription.on('create', spy.create);
subscription.on('update', spy.update);
const obj = new Parse.Object('Test');
obj.set('foo', 'bar');
await obj.save();
obj.set('foo', 'xyz');
obj.set('yolo', 'xyz');
await obj.save();
const obj2 = new Parse.Object('Test');
obj2.set('foo', 'bar');
obj2.set('yolo', 'bar');
await obj2.save();
obj2.set('foo', 'bart');
await obj2.save();
await sleep(2000);
expect(createSpy).toHaveBeenCalledTimes(1);
expect(updateSpy).toHaveBeenCalledTimes(1);
});
it('can handle afterEvent set pointers', async done => {
@@ -469,76 +463,67 @@ describe('ParseLiveQuery', function () {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
Parse.Cloud.beforeSubscribe('TestObject', req => {
expect(req.op).toBe('subscribe');
expect(req.requestId).toBe(1);
expect(req.query).toBeDefined();
expect(req.user).toBeUndefined();
});
Parse.Cloud.beforeConnect(req => {
expect(req.event).toBe('connect');
expect(req.clients).toBe(0);
expect(req.subscriptions).toBe(0);
expect(req.useMasterKey).toBe(false);
expect(req.installationId).toBeDefined();
expect(req.user).toBeUndefined();
expect(req.client).toBeDefined();
});
const hooks = {
beforeSubscribe(req) {
expect(req.op).toBe('subscribe');
expect(req.requestId).toBe(1);
expect(req.query).toBeDefined();
expect(req.user).toBeUndefined();
},
beforeConnect(req) {
expect(req.event).toBe('connect');
expect(req.clients).toBe(0);
expect(req.subscriptions).toBe(0);
expect(req.useMasterKey).toBe(false);
expect(req.installationId).toBeDefined();
expect(req.user).toBeUndefined();
expect(req.client).toBeDefined();
},
};
spyOn(hooks, 'beforeSubscribe').and.callThrough();
spyOn(hooks, 'beforeConnect').and.callThrough();
Parse.Cloud.beforeSubscribe('TestObject', hooks.beforeSubscribe);
Parse.Cloud.beforeConnect(hooks.beforeConnect);
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('update', object => {
expect(object.get('foo')).toBe('bar');
expect(hooks.beforeConnect).toHaveBeenCalled();
expect(hooks.beforeSubscribe).toHaveBeenCalled();
done();
});
object.set({ foo: 'bar' });
await object.save();
});
it('can handle beforeConnect validation function', async done => {
it('can handle beforeConnect validation function', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
Parse.Cloud.beforeConnect(() => {}, validatorFail);
let complete = false;
Parse.LiveQuery.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
if (complete) {
return;
}
complete = true;
expect(error).toBe('you are not authorized');
done();
});
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
await query.subscribe();
await expectAsync(query.subscribe()).toBeRejectedWith(
new Parse.Error(Parse.Error.VALIDATION_ERROR, 'you are not authorized')
);
});
it('can handle beforeSubscribe validation function', async done => {
it('can handle beforeSubscribe validation function', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
@@ -546,11 +531,9 @@ describe('ParseLiveQuery', function () {
Parse.Cloud.beforeSubscribe(TestObject, () => {}, validatorFail);
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('error', error => {
expect(error).toBe('you are not authorized');
done();
});
await expectAsync(query.subscribe()).toBeRejectedWith(
new Parse.Error(Parse.Error.VALIDATION_ERROR, 'you are not authorized')
);
});
it('can handle afterEvent validation function', async done => {
@@ -576,14 +559,12 @@ describe('ParseLiveQuery', function () {
await object.save();
});
it('can handle beforeConnect error', async done => {
it('can handle beforeConnect error', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
@@ -591,14 +572,9 @@ describe('ParseLiveQuery', function () {
Parse.Cloud.beforeConnect(() => {
throw new Error('You shall not pass!');
});
Parse.LiveQuery.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
expect(error).toBe('You shall not pass!');
done();
});
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
await query.subscribe();
await expectAsync(query.subscribe()).toBeRejectedWith(new Error('You shall not pass!'));
});
it('can log on beforeConnect throw', async () => {
@@ -607,8 +583,6 @@ describe('ParseLiveQuery', function () {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const logger = require('../lib/logger').logger;
@@ -620,22 +594,20 @@ describe('ParseLiveQuery', function () {
foo.bar();
/* eslint-enable no-undef */
});
new Parse.Query(TestObject).subscribe();
await new Promise(resolve => Parse.LiveQuery.on('error', resolve));
Parse.LiveQuery.removeAllListeners('error');
await expectAsync(new Parse.Query(TestObject).subscribe()).toBeRejectedWith(
new Error('foo is not defined')
);
expect(logger.error).toHaveBeenCalledWith(
`Failed running beforeConnect for session ${token} with:\n Error: {"message":"foo is not defined","code":141}`
);
});
it('can handle beforeSubscribe error', async done => {
it('can handle beforeSubscribe error', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
await object.save();
@@ -643,17 +615,9 @@ describe('ParseLiveQuery', function () {
Parse.Cloud.beforeSubscribe(TestObject, () => {
throw new Error('You shall not subscribe!');
});
Parse.LiveQuery.on('error', error => {
expect(error).toBe('You shall not subscribe!');
});
const query = new Parse.Query(TestObject);
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
expect(error).toBe('You shall not subscribe!');
done();
});
await expectAsync(query.subscribe()).toBeRejectedWith(new Error('You shall not subscribe!'));
});
it('can log on beforeSubscribe error', async () => {
@@ -662,8 +626,6 @@ describe('ParseLiveQuery', function () {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const logger = require('../lib/logger').logger;
@@ -676,8 +638,7 @@ describe('ParseLiveQuery', function () {
});
const query = new Parse.Query(TestObject);
const subscription = await query.subscribe();
await new Promise(resolve => subscription.on('error', resolve));
await expectAsync(query.subscribe()).toBeRejectedWith(new Error('foo is not defined'));
expect(logger.error).toHaveBeenCalledWith(
`Failed running beforeSubscribe on TestObject for session undefined with:\n Error: {"message":"foo is not defined","code":141}`
@@ -690,29 +651,35 @@ describe('ParseLiveQuery', function () {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.beforeSubscribe(TestObject, request => {
const query = request.query;
query.equalTo('yolo', 'abc');
});
const hook = {
beforeSubscribe(request) {
request.query.equalTo('yolo', 'abc');
},
};
spyOn(hook, 'beforeSubscribe').and.callThrough();
Parse.Cloud.beforeSubscribe('TestObject', hook.beforeSubscribe);
const object = new TestObject();
await object.save();
const query = new Parse.Query(TestObject);
const query = new Parse.Query('TestObject');
query.equalTo('objectId', object.id);
const subscription = await query.subscribe();
subscription.on('update', () => {
fail();
fail('beforeSubscribe should restrict subscription');
});
object.set({ foo: 'bar' });
subscription.on('enter', object => {
if (object.get('yolo') === 'abc') {
done();
} else {
fail('beforeSubscribe should restrict queries');
}
});
object.set({ yolo: 'bar' });
await object.save();
setTimeout(async () => {
done();
}, 1000);
object.set({ yolo: 'abc' });
await object.save();
expect(hook.beforeSubscribe).toHaveBeenCalled();
});
it('can return a new beforeSubscribe query', async done => {
@@ -744,14 +711,6 @@ describe('ParseLiveQuery', function () {
});
it('can handle select beforeSubscribe query', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.Cloud.beforeSubscribe(TestObject, request => {
const query = request.query;
query.select('yolo');
@@ -830,7 +789,7 @@ describe('ParseLiveQuery', function () {
object.set({ foo: 'bar' });
await object.save();
await object.destroy();
await new Promise(resolve => setTimeout(resolve, 200));
await sleep(200);
for (const key in calls) {
expect(calls[key]).toHaveBeenCalled();
}
@@ -864,9 +823,9 @@ describe('ParseLiveQuery', function () {
object.set({ foo: 'bar' });
await object.save(null, { useMasterKey: true });
role.getUsers().add(user);
await new Promise(resolve => setTimeout(resolve, 1000));
await sleep(1000);
await role.save();
await new Promise(resolve => setTimeout(resolve, 1000));
await sleep(1000);
object.set('foo', 'yolo');
await Promise.all([
new Promise(resolve => {
@@ -897,7 +856,6 @@ describe('ParseLiveQuery', function () {
const subscription = await query.subscribe();
subscription.on('create', async obj => {
await new Promise(resolve => setTimeout(resolve, 200));
expect(obj.get('user').id).toBe(user.id);
expect(obj.get('createdWith')).toEqual({ action: 'login', authProvider: 'password' });
expect(obj.get('expiresAt')).toBeInstanceOf(Date);
@@ -910,26 +868,15 @@ describe('ParseLiveQuery', function () {
await Parse.User.logIn('username', 'password');
});
it('prevent liveQuery on Session class when not logged in', async done => {
it('prevent liveQuery on Session class when not logged in', async () => {
await reconfigureServer({
liveQuery: {
classNames: [Parse.Session],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
Parse.LiveQuery.on('error', error => {
expect(error).toBe('Invalid session token');
});
const query = new Parse.Query(Parse.Session);
const subscription = await query.subscribe();
subscription.on('error', error => {
Parse.LiveQuery.removeAllListeners('error');
expect(error).toBe('Invalid session token');
done();
});
await expectAsync(query.subscribe()).toBeRejectedWith(new Error('Invalid session token'));
});
it('handle invalid websocket payload length', async done => {
@@ -977,6 +924,7 @@ describe('ParseLiveQuery', function () {
};
await reconfigureServer({
maintenanceKey: 'test2',
liveQuery: {
classNames: [Parse.User],
},
@@ -998,9 +946,14 @@ describe('ParseLiveQuery', function () {
.signUp()
.then(() => {
const config = Config.get('test');
return config.database.find('_User', {
username: 'zxcv',
});
return config.database.find(
'_User',
{
username: 'zxcv',
},
{},
Auth.maintenance(config)
);
})
.then(async results => {
const foundUser = results[0];
@@ -1076,6 +1029,9 @@ describe('ParseLiveQuery', function () {
user.setUsername('username');
user.setPassword('password');
user.set('foo', 'bar');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
const query = new Parse.Query(Parse.User);
query.equalTo('foo', 'bar');
@@ -1110,12 +1066,169 @@ describe('ParseLiveQuery', function () {
}
});
afterEach(async function (done) {
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
client.close();
// Wait for live query client to disconnect
setTimeout(() => {
it('should strip out protected fields', async () => {
await reconfigureServer({
liveQuery: { classNames: ['Test'] },
startLiveQueryServer: true,
});
const obj1 = new Parse.Object('Test');
obj1.set('foo', 'foo');
obj1.set('bar', 'bar');
obj1.set('qux', 'qux');
await obj1.save();
const config = Config.get(Parse.applicationId);
const schemaController = await config.database.loadSchema();
await schemaController.updateClass(
'Test',
{},
{
get: { '*': true },
find: { '*': true },
update: { '*': true },
protectedFields: {
'*': ['foo'],
},
}
);
const object = await obj1.fetch();
expect(object.get('foo')).toBe(undefined);
expect(object.get('bar')).toBeDefined();
expect(object.get('qux')).toBeDefined();
const subscription = await new Parse.Query('Test').subscribe();
await Promise.all([
new Promise(resolve => {
subscription.on('update', (obj, original) => {
expect(obj.get('foo')).toBe(undefined);
expect(obj.get('bar')).toBeDefined();
expect(obj.get('qux')).toBeDefined();
expect(original.get('foo')).toBe(undefined);
expect(original.get('bar')).toBeDefined();
expect(original.get('qux')).toBeDefined();
resolve();
});
}),
obj1.save({ foo: 'abc' }),
]);
});
it('can subscribe to query and return object with withinKilometers with last parameter on update', async done => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const object = new TestObject();
const firstPoint = new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 });
object.set({ location: firstPoint });
await object.save();
// unsorted will use $centerSphere operator
const sorted = false;
const query = new Parse.Query(TestObject);
query.withinKilometers(
'location',
new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 }),
2,
sorted
);
const subscription = await query.subscribe();
subscription.on('update', obj => {
expect(obj.id).toBe(object.id);
done();
}, 1000);
});
const secondPoint = new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 });
object.set({ location: secondPoint });
await object.save();
});
it('does shutdown liveQuery server', async () => {
await reconfigureServer({ appId: 'test_app_id' });
const config = {
appId: 'hello_test',
masterKey: 'world',
port: 1345,
mountPath: '/1',
serverURL: 'http://localhost:1345/1',
liveQuery: {
classNames: ['Yolo'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
};
if (process.env.PARSE_SERVER_TEST_DB === 'postgres') {
config.databaseAdapter = new databaseAdapter.constructor({
uri: databaseURI,
collectionPrefix: 'test_',
});
config.filesAdapter = defaultConfiguration.filesAdapter;
}
const server = await ParseServer.startApp(config);
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
client.serverURL = 'ws://localhost:1345/1';
const query = await new Parse.Query('Yolo').subscribe();
await Promise.all([
server.handleShutdown(),
new Promise(resolve => query.on('close', resolve)),
]);
await new Promise(resolve => setTimeout(resolve, 100));
expect(server.liveQueryServer.server.address()).toBeNull();
expect(server.liveQueryServer.subscriber.isOpen).toBeFalse();
await new Promise(resolve => server.server.close(resolve));
});
it('prevent afterSave trigger if not exists', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
spyOn(triggers, 'maybeRunTrigger').and.callThrough();
const object1 = new TestObject();
const object2 = new TestObject();
const object3 = new TestObject();
await Parse.Object.saveAll([object1, object2, object3]);
expect(triggers.maybeRunTrigger).toHaveBeenCalledTimes(0);
expect(object1.id).toBeDefined();
expect(object2.id).toBeDefined();
expect(object3.id).toBeDefined();
});
it('triggers query event with constraint not equal to null', async () => {
await reconfigureServer({
liveQuery: {
classNames: ['TestObject'],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
});
const spy = {
create(obj) {
expect(obj.attributes.foo).toEqual('bar');
},
};
const createSpy = spyOn(spy, 'create');
const query = new Parse.Query(TestObject);
query.notEqualTo('foo', null);
const subscription = await query.subscribe();
subscription.on('create', spy.create);
const object1 = new TestObject();
object1.set('foo', 'bar');
await object1.save();
await new Promise(resolve => setTimeout(resolve, 100));
expect(createSpy).toHaveBeenCalledTimes(1);
});
});
+58
View File
@@ -0,0 +1,58 @@
if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
describe('ParseLiveQuery redis', () => {
afterEach(async () => {
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
client.close();
});
it('can connect', async () => {
await reconfigureServer({
appId: 'redis_live_query',
startLiveQueryServer: true,
liveQuery: {
classNames: ['TestObject'],
redisURL: 'redis://localhost:6379',
},
liveQueryServerOptions: {
redisURL: 'redis://localhost:6379',
},
});
const subscription = await new Parse.Query('TestObject').subscribe();
const [object] = await Promise.all([
new Parse.Object('TestObject').save(),
new Promise(resolve =>
subscription.on('create', () => {
resolve();
})
),
]);
await Promise.all([
new Promise(resolve =>
subscription.on('delete', () => {
resolve();
})
),
object.destroy(),
]);
});
it('can call connect twice', async () => {
const server = await reconfigureServer({
appId: 'redis_live_query',
startLiveQueryServer: true,
liveQuery: {
classNames: ['TestObject'],
redisURL: 'redis://localhost:6379',
},
liveQueryServerOptions: {
redisURL: 'redis://localhost:6379',
},
});
expect(server.config.liveQueryController.liveQueryPublisher.parsePublisher.isOpen).toBeTrue();
await server.config.liveQueryController.connect();
expect(server.config.liveQueryController.liveQueryPublisher.parsePublisher.isOpen).toBeTrue();
expect(server.liveQueryServer.subscriber.isOpen).toBe(true);
await server.liveQueryServer.connect();
expect(server.liveQueryServer.subscriber.isOpen).toBe(true);
});
});
}
+124 -36
View File
@@ -94,29 +94,30 @@ describe('ParseLiveQueryServer', function () {
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
});
it('can be initialized from ParseServer', function () {
it('can be initialized from ParseServer', async () => {
const httpServer = {};
const parseLiveQueryServer = ParseServer.createLiveQueryServer(httpServer, {});
const parseLiveQueryServer = await ParseServer.createLiveQueryServer(httpServer, {});
expect(parseLiveQueryServer.clientId).toBeUndefined();
expect(parseLiveQueryServer.clients.size).toBe(0);
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
});
it('can be initialized from ParseServer without httpServer', function (done) {
const parseLiveQueryServer = ParseServer.createLiveQueryServer(undefined, {
it('can be initialized from ParseServer without httpServer', async () => {
const parseLiveQueryServer = await ParseServer.createLiveQueryServer(undefined, {
port: 22345,
});
expect(parseLiveQueryServer.clientId).toBeUndefined();
expect(parseLiveQueryServer.clients.size).toBe(0);
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
parseLiveQueryServer.server.close(done);
await new Promise(resolve => parseLiveQueryServer.server.close(resolve));
});
describe_only_db('mongo')('initialization', () => {
it('can be initialized through ParseServer without liveQueryServerOptions', function (done) {
const parseServer = ParseServer.start({
beforeEach(() => reconfigureServer({ appId: 'mongo_init_test' }));
it('can be initialized through ParseServer without liveQueryServerOptions', async () => {
const parseServer = await ParseServer.startApp({
appId: 'hello',
masterKey: 'world',
port: 22345,
@@ -126,19 +127,14 @@ describe('ParseLiveQueryServer', function () {
classNames: ['Yolo'],
},
startLiveQueryServer: true,
serverStartComplete: () => {
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).toBe(parseServer.server);
parseServer.server.close(async () => {
await reconfigureServer();
done();
});
},
});
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).toBe(parseServer.server);
await new Promise(resolve => parseServer.server.close(resolve));
});
it('can be initialized through ParseServer with liveQueryServerOptions', function (done) {
const parseServer = ParseServer.start({
it('can be initialized through ParseServer with liveQueryServerOptions', async () => {
const parseServer = await ParseServer.startApp({
appId: 'hello',
masterKey: 'world',
port: 22346,
@@ -150,17 +146,10 @@ describe('ParseLiveQueryServer', function () {
liveQueryServerOptions: {
port: 22347,
},
serverStartComplete: () => {
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).not.toBe(parseServer.server);
parseServer.liveQueryServer.server.close(
parseServer.server.close.bind(parseServer.server, async () => {
await reconfigureServer();
done();
})
);
},
});
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).not.toBe(parseServer.server);
await new Promise(resolve => parseServer.server.close(resolve));
});
});
@@ -306,7 +295,7 @@ describe('ParseLiveQueryServer', function () {
where: {
key: 'value',
},
fields: ['test'],
keys: ['test'],
};
const requestId = 2;
const request = {
@@ -343,7 +332,7 @@ describe('ParseLiveQueryServer', function () {
where: {
key: 'value',
},
fields: ['test'],
keys: ['test'],
};
const requestId = 2;
const request = {
@@ -367,7 +356,7 @@ describe('ParseLiveQueryServer', function () {
// Make sure we add subscriptionInfo to the client
const args = client.addSubscriptionInfo.calls.first().args;
expect(args[0]).toBe(requestId);
expect(args[1].fields).toBe(query.fields);
expect(args[1].keys).toBe(query.keys);
expect(args[1].sessionToken).toBe(request.sessionToken);
// Make sure we send subscribe response to the client
expect(client.pushSubscribe).toHaveBeenCalledWith(requestId);
@@ -390,7 +379,7 @@ describe('ParseLiveQueryServer', function () {
where: {
key: 'value',
},
fields: ['test'],
keys: ['test'],
};
await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query);
// Add subscription for mock client 2
@@ -402,7 +391,7 @@ describe('ParseLiveQueryServer', function () {
where: {
key: 'value',
},
fields: ['testAgain'],
keys: ['testAgain'],
};
const requestIdAgain = 1;
await addMockSubscription(
@@ -428,7 +417,7 @@ describe('ParseLiveQueryServer', function () {
// Make sure we add subscriptionInfo to the client 2
args = clientAgain.addSubscriptionInfo.calls.mostRecent().args;
expect(args[0]).toBe(requestIdAgain);
expect(args[1].fields).toBe(queryAgain.fields);
expect(args[1].keys).toBe(queryAgain.keys);
});
it('can handle unsubscribe command without clientId', function () {
@@ -766,6 +755,49 @@ describe('ParseLiveQueryServer', function () {
parseLiveQueryServer._onAfterSave(message);
});
it('sends correct object for dates', async () => {
jasmine.restoreLibrary('../lib/LiveQuery/QueryTools', 'matchesQuery');
const parseLiveQueryServer = new ParseLiveQueryServer({});
const date = new Date();
const message = {
currentParseObject: {
date: { __type: 'Date', iso: date.toISOString() },
__type: 'Object',
key: 'value',
className: testClassName,
},
};
// Add mock client
const clientId = 1;
const client = addMockClient(parseLiveQueryServer, clientId);
const requestId2 = 2;
await addMockSubscription(parseLiveQueryServer, clientId, requestId2);
parseLiveQueryServer._matchesACL = function () {
return Promise.resolve(true);
};
parseLiveQueryServer._inflateParseObject(message);
parseLiveQueryServer._onAfterSave(message);
// Make sure we send leave and enter command to client
await timeout();
expect(client.pushCreate).toHaveBeenCalledWith(
requestId2,
{
className: 'TestObject',
key: 'value',
date: { __type: 'Date', iso: date.toISOString() },
},
null
);
});
it('can handle object save command which does not match any subscription', async done => {
const parseLiveQueryServer = new ParseLiveQueryServer({});
// Make mock request message
@@ -1049,7 +1081,7 @@ describe('ParseLiveQueryServer', function () {
done();
});
it('can handle create command with fields', async done => {
it('can handle create command with keys', async done => {
jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client');
const Client = require('../lib/LiveQuery/Client').Client;
const parseLiveQueryServer = new ParseLiveQueryServer({});
@@ -1072,7 +1104,7 @@ describe('ParseLiveQueryServer', function () {
where: {
key: 'value',
},
fields: ['test'],
keys: ['test'],
};
await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query);
// Mock _matchesSubscription to return matching
@@ -1099,6 +1131,61 @@ describe('ParseLiveQueryServer', function () {
done();
});
it('can handle create command with watch', async () => {
jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client');
const Client = require('../lib/LiveQuery/Client').Client;
const parseLiveQueryServer = new ParseLiveQueryServer({});
// Make mock request message
const message = generateMockMessage();
const clientId = 1;
const parseWebSocket = {
clientId,
send: jasmine.createSpy('send'),
};
const client = new Client(clientId, parseWebSocket);
spyOn(client, 'pushCreate').and.callThrough();
parseLiveQueryServer.clients.set(clientId, client);
// Add mock subscription
const requestId = 2;
const query = {
className: testClassName,
where: {
key: 'value',
},
watch: ['yolo'],
};
await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query);
// Mock _matchesSubscription to return matching
parseLiveQueryServer._matchesSubscription = function (parseObject) {
if (!parseObject) {
return false;
}
return true;
};
parseLiveQueryServer._matchesACL = function () {
return Promise.resolve(true);
};
parseLiveQueryServer._onAfterSave(message);
// Make sure we send create command to client
await timeout();
expect(client.pushCreate).not.toHaveBeenCalled();
message.currentParseObject.set('yolo', 'test');
parseLiveQueryServer._onAfterSave(message);
await timeout();
const args = parseWebSocket.send.calls.mostRecent().args;
const toSend = JSON.parse(args[0]);
expect(toSend.object).toBeDefined();
expect(toSend.original).toBeUndefined();
});
it('can match subscription for null or undefined parse object', function () {
const parseLiveQueryServer = new ParseLiveQueryServer({});
// Make mock subscription
@@ -1822,7 +1909,7 @@ describe('ParseLiveQueryServer', function () {
where: {
key: 'value',
},
fields: ['test'],
keys: ['test'],
};
}
const request = {
@@ -1846,6 +1933,7 @@ describe('ParseLiveQueryServer', function () {
} else {
subscription.clientRequestIds = new Map([[clientId, [requestId]]]);
}
subscription.query = query.where;
return subscription;
}
+116
View File
@@ -568,6 +568,70 @@ describe('Parse.Object testing', () => {
);
});
it_only_db('mongo')('can increment array nested fields', async () => {
const obj = new TestObject();
obj.set('items', [ { value: 'a', count: 5 }, { value: 'b', count: 1 } ]);
await obj.save();
obj.increment('items.0.count', 15);
obj.increment('items.1.count', 4);
await obj.save();
expect(obj.toJSON().items[0].value).toBe('a');
expect(obj.toJSON().items[1].value).toBe('b');
expect(obj.toJSON().items[0].count).toBe(20);
expect(obj.toJSON().items[1].count).toBe(5);
const query = new Parse.Query(TestObject);
const result = await query.get(obj.id);
expect(result.get('items')[0].value).toBe('a');
expect(result.get('items')[1].value).toBe('b');
expect(result.get('items')[0].count).toBe(20);
expect(result.get('items')[1].count).toBe(5);
expect(result.get('items')).toEqual(obj.get('items'));
});
it_only_db('mongo')('can increment array nested fields missing index', async () => {
const obj = new TestObject();
obj.set('items', []);
await obj.save();
obj.increment('items.1.count', 15);
await obj.save();
expect(obj.toJSON().items[0]).toBe(null);
expect(obj.toJSON().items[1].count).toBe(15);
const query = new Parse.Query(TestObject);
const result = await query.get(obj.id);
expect(result.get('items')[0]).toBe(null);
expect(result.get('items')[1].count).toBe(15);
expect(result.get('items')).toEqual(obj.get('items'));
});
it('can query array nested fields', async () => {
const objects = [];
for (let i = 0; i < 10; i++) {
const obj = new TestObject();
obj.set('items', [i, { value: i }]);
objects.push(obj);
}
await Parse.Object.saveAll(objects);
let query = new Parse.Query(TestObject);
query.greaterThan('items.1.value', 5);
let result = await query.find();
expect(result.length).toBe(4);
query = new Parse.Query(TestObject);
query.lessThan('items.0', 3);
result = await query.find();
expect(result.length).toBe(3);
query = new Parse.Query(TestObject);
query.equalTo('items.0', 5);
result = await query.find();
expect(result.length).toBe(1);
query = new Parse.Query(TestObject);
query.notEqualTo('items.0', 5);
result = await query.find();
expect(result.length).toBe(9);
});
it('addUnique with object', function (done) {
const x1 = new Parse.Object('X');
x1.set('stuff', [1, { hello: 'world' }, { foo: 'bar' }]);
@@ -2055,4 +2119,56 @@ describe('Parse.Object testing', () => {
const object = new Parse.Object('CloudCodeIsNew');
await object.save();
});
it('should not change the json field to array in afterSave', async () => {
Parse.Cloud.beforeSave('failingJSONTestCase', req => {
expect(req.object.get('jsonField')).toEqual({ '123': 'test' });
});
Parse.Cloud.afterSave('failingJSONTestCase', req => {
expect(req.object.get('jsonField')).toEqual({ '123': 'test' });
});
const object = new Parse.Object('failingJSONTestCase');
object.set('jsonField', { '123': 'test' });
await object.save();
});
it('returns correct field values', async () => {
const values = [
{ field: 'string', value: 'string' },
{ field: 'number', value: 1 },
{ field: 'boolean', value: true },
{ field: 'array', value: [0, 1, 2] },
{ field: 'array', value: [1, 2, 3] },
{ field: 'array', value: [{ '0': 'a' }, 2, 3] },
{ field: 'object', value: { key: 'value' } },
{ field: 'object', value: { key1: 'value1', key2: 'value2' } },
{ field: 'object', value: { key1: 1, key2: 2 } },
{ field: 'object', value: { '1x1': 1 } },
{ field: 'object', value: { '1x1': 1, '2': 2 } },
{ field: 'object', value: { '0': 0 } },
{ field: 'object', value: { '1': 1 } },
{ field: 'object', value: { '0': { '0': 'a', '1': 'b' } } },
{ field: 'date', value: new Date() },
{
field: 'file',
value: Parse.File.fromJSON({
__type: 'File',
name: 'name',
url: 'http://localhost:8378/1/files/test/name',
}),
},
{ field: 'geoPoint', value: new Parse.GeoPoint(40, -30) },
{ field: 'bytes', value: { __type: 'Bytes', base64: 'ZnJveW8=' } },
];
for (const value of values) {
const object = new TestObject();
object.set(value.field, value.value);
await object.save();
const query = new Parse.Query(TestObject);
const objectAgain = await query.get(object.id);
expect(objectAgain.get(value.field)).toEqual(value.value);
}
});
});
+90 -84
View File
@@ -23,28 +23,28 @@ const loadTestData = () => {
const data1 = {
score: 10,
name: 'foo',
sender: { group: 'A' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
sender: { group: 'A' },
views: 900,
size: ['S', 'M'],
};
const data2 = {
score: 10,
name: 'foo',
sender: { group: 'A' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
sender: { group: 'A' },
views: 800,
size: ['M', 'L'],
};
const data3 = {
score: 10,
name: 'bar',
sender: { group: 'B' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
sender: { group: 'B' },
views: 700,
size: ['S'],
};
const data4 = {
score: 20,
name: 'dpl',
sender: { group: 'B' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
sender: { group: 'B' },
views: 700,
size: ['S'],
};
@@ -86,7 +86,7 @@ describe('Parse.Query Aggregate testing', () => {
it('invalid query group _id required', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: {}, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
$group: {},
},
});
get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
@@ -98,7 +98,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group by field', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: '$name' }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
$group: { _id: '$name' },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -119,7 +119,7 @@ describe('Parse.Query Aggregate testing', () => {
const options = Object.assign({}, masterKeyOptions, {
body: {
pipeline: {
group: { objectId: '$name' }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
$group: { _id: '$name' },
},
},
});
@@ -137,7 +137,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj = new TestObject();
const pipeline = [
{
group: { objectId: {} }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
$group: { _id: {} },
},
];
obj
@@ -156,7 +156,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj = new TestObject();
const pipeline = [
{
group: { objectId: '' }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
$group: { _id: '' },
},
];
obj
@@ -175,7 +175,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj = new TestObject();
const pipeline = [
{
group: { objectId: [] }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
$group: { _id: [] },
},
];
obj
@@ -196,9 +196,8 @@ describe('Parse.Query Aggregate testing', () => {
const obj3 = new TestObject();
const pipeline = [
{
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: {
objectId: {
$group: {
_id: {
score: '$score',
views: '$views',
},
@@ -280,7 +279,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group by number', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: '$score' }, // TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
$group: { _id: '$score' },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -302,9 +301,8 @@ describe('Parse.Query Aggregate testing', () => {
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
const pipeline = [
{
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: {
objectId: null,
$group: {
_id: null,
total: { $sum: { $multiply: ['$quantity', '$price'] } },
},
},
@@ -326,10 +324,10 @@ describe('Parse.Query Aggregate testing', () => {
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
const pipeline = [
{
match: { quantity: { $exists: true } },
$match: { quantity: { $exists: true } },
},
{
project: {
$project: {
name: 1,
total: { $multiply: ['$quantity', '$price'] },
},
@@ -358,16 +356,16 @@ describe('Parse.Query Aggregate testing', () => {
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
const pipeline = [
{
match: { quantity: { $exists: true } },
$match: { quantity: { $exists: true } },
},
{
project: {
objectId: 0, // TODO: change to `_id`. See [#7339](https://bit.ly/3incnWx)
$project: {
_id: 0,
total: { $multiply: ['$quantity', '$price'] },
},
},
{
sort: { total: 1 },
$sort: { total: 1 },
},
];
Parse.Object.saveAll([obj1, obj2])
@@ -388,7 +386,7 @@ describe('Parse.Query Aggregate testing', () => {
it_exclude_dbs(['postgres'])('project updatedAt only transform', done => {
const pipeline = [
{
project: { objectId: 0, updatedAt: 1 },
$project: { _id: 0, updatedAt: 1 },
},
];
const query = new Parse.Query(TestObject);
@@ -411,13 +409,13 @@ describe('Parse.Query Aggregate testing', () => {
const obj3 = new TestObject({ dateField2019: new Date(1990, 11, 1) });
const pipeline = [
{
match: {
$match: {
dateField2019: { $exists: true },
},
},
{
group: {
objectId: {
$group: {
_id: {
day: { $dayOfMonth: '$dateField2019' },
month: { $month: '$dateField2019' },
year: { $year: '$dateField2019' },
@@ -449,9 +447,8 @@ describe('Parse.Query Aggregate testing', () => {
const obj3 = new TestObject({ dateField2019: new Date(1990, 11, 1) });
const pipeline = [
{
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: {
objectId: {
$group: {
_id: {
day: { $dayOfMonth: '$dateField2019' },
month: { $month: '$dateField2019' },
year: { $year: '$dateField2019' },
@@ -481,7 +478,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj1 = new TestObject({ pointer: pointer1 });
const obj2 = new TestObject({ pointer: pointer2 });
const obj3 = new TestObject({ pointer: pointer1 });
const pipeline = [{ group: { objectId: '$pointer' } }];
const pipeline = [{ $group: { _id: '$pointer' } }];
Parse.Object.saveAll([pointer1, pointer2, obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
@@ -499,8 +496,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group sum query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, total: { $sum: '$score' } },
$group: { _id: null, total: { $sum: '$score' } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -516,8 +512,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group count query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, total: { $sum: 1 } },
$group: { _id: null, total: { $sum: 1 } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -533,8 +528,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group min query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, minScore: { $min: '$score' } },
$group: { _id: null, minScore: { $min: '$score' } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -550,8 +544,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group max query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, maxScore: { $max: '$score' } },
$group: { _id: null, maxScore: { $max: '$score' } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -567,8 +560,7 @@ describe('Parse.Query Aggregate testing', () => {
it('group avg query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, avgScore: { $avg: '$score' } },
$group: { _id: null, avgScore: { $avg: '$score' } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -584,7 +576,7 @@ describe('Parse.Query Aggregate testing', () => {
it('limit query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
limit: 2,
$limit: 2,
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -598,7 +590,7 @@ describe('Parse.Query Aggregate testing', () => {
it('sort ascending query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
sort: { name: 1 },
$sort: { name: 1 },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -616,7 +608,7 @@ describe('Parse.Query Aggregate testing', () => {
it('sort decending query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
sort: { name: -1 },
$sort: { name: -1 },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -634,7 +626,7 @@ describe('Parse.Query Aggregate testing', () => {
it('skip query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
skip: 2,
$skip: 2,
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -654,7 +646,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj1 = new TestObject({ dateField: yesterday });
const obj2 = new TestObject({ dateField: today });
const obj3 = new TestObject({ dateField: tomorrow });
const pipeline = [{ match: { dateField: { $lt: tomorrow } } }];
const pipeline = [{ $match: { dateField: { $lt: tomorrow } } }];
Parse.Object.saveAll([obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
@@ -666,10 +658,27 @@ describe('Parse.Query Aggregate testing', () => {
});
});
it('should aggregate with Date object (directAccess)', async () => {
const rest = require('../lib/rest');
const auth = require('../lib/Auth');
const TestObject = Parse.Object.extend('TestObject');
const date = new Date();
await new TestObject({ date: date }).save(null, { useMasterKey: true });
const config = Config.get(Parse.applicationId);
const resp = await rest.find(
config,
auth.master(config),
'TestObject',
{},
{ pipeline: [{ $match: { date: { $lte: new Date() } } }] }
);
expect(resp.results.length).toBe(1);
});
it('match comparison query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 15 } },
$match: { score: { $gt: 15 } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -684,7 +693,7 @@ describe('Parse.Query Aggregate testing', () => {
it('match multiple comparison query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 5, $lt: 15 } },
$match: { score: { $gt: 5, $lt: 15 } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -701,7 +710,7 @@ describe('Parse.Query Aggregate testing', () => {
it('match complex comparison query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 5, $lt: 15 }, views: { $gt: 850, $lt: 1000 } },
$match: { score: { $gt: 5, $lt: 15 }, views: { $gt: 850, $lt: 1000 } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -717,7 +726,7 @@ describe('Parse.Query Aggregate testing', () => {
it('match comparison and equality query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 5, $lt: 15 }, views: 900 },
$match: { score: { $gt: 5, $lt: 15 }, views: 900 },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -733,7 +742,7 @@ describe('Parse.Query Aggregate testing', () => {
it('match $or query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: {
$match: {
$or: [{ score: { $gt: 15, $lt: 25 } }, { views: { $gt: 750, $lt: 850 } }],
},
},
@@ -758,7 +767,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj2 = new TestObject();
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const pipeline = [{ match: { objectId: obj1.id } }];
const pipeline = [{ $match: { _id: obj1.id } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -774,7 +783,7 @@ describe('Parse.Query Aggregate testing', () => {
const obj2 = new TestObject({ name: 'TestObject2' });
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const pipeline = [{ match: { name: 'TestObject1' } }];
const pipeline = [{ $match: { name: 'TestObject1' } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -794,7 +803,7 @@ describe('Parse.Query Aggregate testing', () => {
Parse.Object.saveAll([pointer1, pointer2, obj1, obj2, obj3])
.then(() => {
const pipeline = [{ match: { pointer: pointer1.id } }];
const pipeline = [{ $match: { pointer: pointer1.id } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -809,7 +818,7 @@ describe('Parse.Query Aggregate testing', () => {
});
it_exclude_dbs(['postgres'])('match exists query', done => {
const pipeline = [{ match: { score: { $exists: true } } }];
const pipeline = [{ $match: { score: { $exists: true } } }];
const query = new Parse.Query(TestObject);
query.aggregate(pipeline).then(results => {
expect(results.length).toEqual(4);
@@ -825,7 +834,7 @@ describe('Parse.Query Aggregate testing', () => {
.then(() => {
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const pipeline = [{ match: { createdAt: { $gte: today } } }];
const pipeline = [{ $match: { createdAt: { $gte: today } } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -844,7 +853,7 @@ describe('Parse.Query Aggregate testing', () => {
.then(() => {
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const pipeline = [{ match: { updatedAt: { $gte: today } } }];
const pipeline = [{ $match: { updatedAt: { $gte: today } } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -863,7 +872,7 @@ describe('Parse.Query Aggregate testing', () => {
.then(() => {
const now = new Date();
const future = new Date(now.getFullYear(), now.getMonth() + 1, now.getDate());
const pipeline = [{ match: { createdAt: future } }];
const pipeline = [{ $match: { createdAt: future } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -882,7 +891,7 @@ describe('Parse.Query Aggregate testing', () => {
Parse.Object.saveAll([pointer, obj1, obj2, obj3])
.then(() => {
const pipeline = [{ match: { pointer: { $exists: true } } }];
const pipeline = [{ $match: { pointer: { $exists: true } } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
@@ -921,7 +930,7 @@ describe('Parse.Query Aggregate testing', () => {
(
await new Parse.Query('MyCollection').aggregate([
{
match: {
$match: {
language: { $in: [null, 'en'] },
},
},
@@ -935,7 +944,7 @@ describe('Parse.Query Aggregate testing', () => {
(
await new Parse.Query('MyCollection').aggregate([
{
match: {
$match: {
$or: [{ language: 'en' }, { language: null }],
},
},
@@ -949,7 +958,7 @@ describe('Parse.Query Aggregate testing', () => {
it('project query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
project: { name: 1 },
$project: { name: 1 },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -969,7 +978,7 @@ describe('Parse.Query Aggregate testing', () => {
it('multiple project query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
project: { name: 1, score: 1, sender: 1 },
$project: { name: 1, score: 1, sender: 1 },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -994,8 +1003,8 @@ describe('Parse.Query Aggregate testing', () => {
.save()
.then(() => {
const pipeline = [
{ match: { objectId: obj.id } },
{ project: { pointer: 1, name: 1, createdAt: 1 } },
{ $match: { _id: obj.id } },
{ $project: { pointer: 1, name: 1, createdAt: 1 } },
];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
@@ -1012,9 +1021,8 @@ describe('Parse.Query Aggregate testing', () => {
it('project with group query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
project: { score: 1 },
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: '$score', score: { $sum: '$score' } },
$project: { score: 1 },
$group: { _id: '$score', score: { $sum: '$score' } },
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -1041,8 +1049,7 @@ describe('Parse.Query Aggregate testing', () => {
it('class does not exist return empty', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, total: { $sum: '$score' } },
$group: { _id: null, total: { $sum: '$score' } },
},
});
get(Parse.serverURL + '/aggregate/UnknownClass', options)
@@ -1056,8 +1063,7 @@ describe('Parse.Query Aggregate testing', () => {
it('field does not exist return empty', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
group: { objectId: null, total: { $sum: '$unknownfield' } },
$group: { _id: null, total: { $sum: '$unknownfield' } },
},
});
get(Parse.serverURL + '/aggregate/UnknownClass', options)
@@ -1086,7 +1092,7 @@ describe('Parse.Query Aggregate testing', () => {
const options = Object.assign({}, masterKeyOptions, {
body: {
distinct: 'score',
where: {
$where: {
name: 'bar',
},
},
@@ -1103,7 +1109,7 @@ describe('Parse.Query Aggregate testing', () => {
const options = Object.assign({}, masterKeyOptions, {
body: {
distinct: 'score',
where: JSON.stringify({ name: 'bar' }),
$where: JSON.stringify({ name: 'bar' }),
},
});
get(Parse.serverURL + '/aggregate/TestObject', options)
@@ -1253,7 +1259,7 @@ describe('Parse.Query Aggregate testing', () => {
it('does not return sensitive hidden properties', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: {
$match: {
score: {
$gt: 5,
},
@@ -1300,7 +1306,7 @@ describe('Parse.Query Aggregate testing', () => {
});
it_exclude_dbs(['postgres'])('aggregate allow multiple of same stage', async done => {
await reconfigureServer();
await reconfigureServer({ silent: false });
const pointer1 = new TestObject({ value: 1 });
const pointer2 = new TestObject({ value: 2 });
const pointer3 = new TestObject({ value: 3 });
@@ -1313,17 +1319,17 @@ describe('Parse.Query Aggregate testing', () => {
body: {
pipeline: [
{
match: { name: 'Hello' },
$match: { name: 'Hello' },
},
{
// Transform className$objectId to objectId and store in new field tempPointer
project: {
$project: {
tempPointer: { $substr: ['$_p_pointer', 11, -1] }, // Remove TestObject$
},
},
{
// Left Join, replace objectId stored in tempPointer with an actual object
lookup: {
$lookup: {
from: 'test_TestObject',
localField: 'tempPointer',
foreignField: '_id',
@@ -1332,12 +1338,12 @@ describe('Parse.Query Aggregate testing', () => {
},
{
// lookup returns an array, Deconstructs an array field to objects
unwind: {
$unwind: {
path: '$tempPointer',
},
},
{
match: { 'tempPointer.value': 2 },
$match: { 'tempPointer.value': 2 },
},
],
},
@@ -1381,7 +1387,7 @@ describe('Parse.Query Aggregate testing', () => {
// Create query
const pipeline = [
{
geoNear: {
$geoNear: {
near: {
type: 'Point',
coordinates: [1, 1],
@@ -1434,7 +1440,7 @@ describe('Parse.Query Aggregate testing', () => {
// Create query
const pipeline = [
{
geoNear: {
$geoNear: {
near: {
type: 'Point',
coordinates: [1, 1],
@@ -1480,7 +1486,7 @@ describe('Parse.Query Aggregate testing', () => {
// Create query
const pipeline = [
{
geoNear: {
$geoNear: {
near: [1, 1],
key: 'location',
spherical: true,
+109
View File
@@ -0,0 +1,109 @@
'use strict';
const Config = require('../lib/Config');
const { MongoClient } = require('mongodb');
const databaseURI = 'mongodb://localhost:27017/';
const request = require('../lib/request');
let config, client, database;
const masterKeyHeaders = {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'rest',
'X-Parse-Master-Key': 'test',
'Content-Type': 'application/json',
};
const masterKeyOptions = {
headers: masterKeyHeaders,
json: true,
};
const profileLevel = 2;
describe_only_db('mongo')('Parse.Query with comment testing', () => {
beforeAll(async () => {
config = Config.get('test');
client = await MongoClient.connect(databaseURI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
database = client.db('parseServerMongoAdapterTestDatabase');
let profiler = await database.command({ profile: 0 });
expect(profiler.was).toEqual(0);
// console.log(`Disabling profiler : ${profiler.was}`);
profiler = await database.command({ profile: profileLevel });
profiler = await database.command({ profile: -1 });
// console.log(`Enabling profiler : ${profiler.was}`);
profiler = await database.command({ profile: -1 });
expect(profiler.was).toEqual(profileLevel);
});
beforeEach(async () => {
const profiler = await database.command({ profile: -1 });
expect(profiler.was).toEqual(profileLevel);
});
afterAll(async () => {
await database.command({ profile: 0 });
await client.close();
});
it('send comment with query through REST', async () => {
const comment = 'Hello Parse';
const object = new TestObject();
object.set('name', 'object');
await object.save();
const options = Object.assign({}, masterKeyOptions, {
url: Parse.serverURL + '/classes/TestObject',
qs: {
explain: true,
comment: comment,
},
});
await request(options);
const result = await database.collection('system.profile').findOne({}, { sort: { ts: -1 } });
expect(result.command.explain.comment).toBe(comment);
});
it('send comment with query', async () => {
const comment = 'Hello Parse';
const object = new TestObject();
object.set('name', 'object');
await object.save();
const collection = await config.database.adapter._adaptiveCollection('TestObject');
await collection._rawFind({ name: 'object' }, { comment: comment });
const result = await database.collection('system.profile').findOne({}, { sort: { ts: -1 } });
expect(result.command.comment).toBe(comment);
});
it('send a comment with a count query', async () => {
const comment = 'Hello Parse';
const object = new TestObject();
object.set('name', 'object');
await object.save();
const object2 = new TestObject();
object2.set('name', 'object');
await object2.save();
const collection = await config.database.adapter._adaptiveCollection('TestObject');
const countResult = await collection.count({ name: 'object' }, { comment: comment });
expect(countResult).toEqual(2);
const result = await database.collection('system.profile').findOne({}, { sort: { ts: -1 } });
expect(result.command.comment).toBe(comment);
});
it('attach a comment to an aggregation', async () => {
const comment = 'Hello Parse';
const object = new TestObject();
object.set('name', 'object');
await object.save();
const collection = await config.database.adapter._adaptiveCollection('TestObject');
await collection.aggregate([{ $group: { _id: '$name' } }], {
explain: true,
comment: comment,
});
const result = await database.collection('system.profile').findOne({}, { sort: { ts: -1 } });
expect(result.command.explain.comment).toBe(comment);
});
});
+16 -14
View File
@@ -27,7 +27,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
await TestUtils.destroyAllDataPermanently(false);
});
it_only_mongodb_version('<5.1')('query find with hint string', async () => {
it_only_mongodb_version('<5.1>=6')('query find with hint string', async () => {
const object = new TestObject();
await object.save();
@@ -39,7 +39,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
expect(explain.queryPlanner.winningPlan.inputStage.indexName).toBe('_id_');
});
it_only_mongodb_version('>=5.1')('query find with hint string', async () => {
it_only_mongodb_version('>=5.1<6')('query find with hint string', async () => {
const object = new TestObject();
await object.save();
@@ -50,7 +50,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
expect(explain.queryPlanner.winningPlan.queryPlan.inputStage.indexName).toBe('_id_');
});
it_only_mongodb_version('<5.1')('query find with hint object', async () => {
it_only_mongodb_version('<5.1>=6')('query find with hint object', async () => {
const object = new TestObject();
await object.save();
@@ -64,7 +64,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
});
});
it_only_mongodb_version('>=5.1')('query find with hint object', async () => {
it_only_mongodb_version('>=5.1<6')('query find with hint object', async () => {
const object = new TestObject();
await object.save();
@@ -86,6 +86,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
let result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
explain: true,
});
let { queryPlanner } = result[0].stages[0].$cursor;
expect(queryPlanner.winningPlan.stage).toBe('COLLSCAN');
@@ -93,6 +94,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
hint: '_id_',
explain: true,
});
queryPlanner = result[0].stages[0].$cursor.queryPlanner;
expect(queryPlanner.winningPlan.stage).toBe('FETCH');
expect(queryPlanner.winningPlan.inputStage.indexName).toBe('_id_');
@@ -265,7 +267,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
expect(queryPlanner.winningPlan.queryPlan.inputStage.inputStage.keyPattern).toEqual({ _id: 1 });
});
it_only_mongodb_version('<5.1')('query find with hint (rest)', async () => {
it_only_mongodb_version('<5.1>=6')('query find with hint (rest)', async () => {
const object = new TestObject();
await object.save();
let options = Object.assign({}, masterKeyOptions, {
@@ -290,7 +292,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
expect(explain.queryPlanner.winningPlan.inputStage.inputStage.indexName).toBe('_id_');
});
it_only_mongodb_version('>=5.1')('query find with hint (rest)', async () => {
it_only_mongodb_version('>=5.1<6')('query find with hint (rest)', async () => {
const object = new TestObject();
await object.save();
let options = Object.assign({}, masterKeyOptions, {
@@ -322,7 +324,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
url: Parse.serverURL + '/aggregate/TestObject',
qs: {
explain: true,
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
let response = await request(options);
@@ -334,7 +336,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
qs: {
explain: true,
hint: '_id_',
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
response = await request(options);
@@ -349,7 +351,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
url: Parse.serverURL + '/aggregate/TestObject',
qs: {
explain: true,
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
let response = await request(options);
@@ -363,7 +365,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
qs: {
explain: true,
hint: '_id_',
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
response = await request(options);
@@ -382,7 +384,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
url: Parse.serverURL + '/aggregate/TestObject',
qs: {
explain: true,
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
let response = await request(options);
@@ -396,7 +398,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
qs: {
explain: true,
hint: '_id_',
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
response = await request(options);
@@ -415,7 +417,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
url: Parse.serverURL + '/aggregate/TestObject',
qs: {
explain: true,
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
let response = await request(options);
@@ -429,7 +431,7 @@ describe_only_db('mongo')('Parse.Query hint', () => {
qs: {
explain: true,
hint: '_id_',
group: JSON.stringify({ objectId: '$foo' }),
$group: JSON.stringify({ _id: '$foo' }),
},
});
response = await request(options);
+49 -21
View File
@@ -314,39 +314,57 @@ describe('Parse.Query testing', () => {
equal(results.length, 0);
});
it('query with limit', function (done) {
const baz = new TestObject({ foo: 'baz' });
const qux = new TestObject({ foo: 'qux' });
Parse.Object.saveAll([baz, qux]).then(function () {
const query = new Parse.Query(TestObject);
query.limit(1);
query.find().then(function (results) {
equal(results.length, 1);
done();
});
});
it('query without limit respects default limit', async () => {
await reconfigureServer({ defaultLimit: 1 });
const obj1 = new TestObject({ foo: 'baz' });
const obj2 = new TestObject({ foo: 'qux' });
await Parse.Object.saveAll([obj1, obj2]);
const query = new Parse.Query(TestObject);
const result = await query.find();
expect(result.length).toBe(1);
});
it('query with limit', async () => {
const obj1 = new TestObject({ foo: 'baz' });
const obj2 = new TestObject({ foo: 'qux' });
await Parse.Object.saveAll([obj1, obj2]);
const query = new Parse.Query(TestObject);
query.limit(1);
const result = await query.find();
expect(result.length).toBe(1);
});
it('query with limit overrides default limit', async () => {
await reconfigureServer({ defaultLimit: 2 });
const obj1 = new TestObject({ foo: 'baz' });
const obj2 = new TestObject({ foo: 'qux' });
await Parse.Object.saveAll([obj1, obj2]);
const query = new Parse.Query(TestObject);
query.limit(1);
const result = await query.find();
expect(result.length).toBe(1);
});
it('query with limit equal to maxlimit', async () => {
const baz = new TestObject({ foo: 'baz' });
const qux = new TestObject({ foo: 'qux' });
await reconfigureServer({ maxLimit: 1 });
await Parse.Object.saveAll([baz, qux]);
const obj1 = new TestObject({ foo: 'baz' });
const obj2 = new TestObject({ foo: 'qux' });
await Parse.Object.saveAll([obj1, obj2]);
const query = new Parse.Query(TestObject);
query.limit(1);
const results = await query.find();
equal(results.length, 1);
const result = await query.find();
expect(result.length).toBe(1);
});
it('query with limit exceeding maxlimit', async () => {
const baz = new TestObject({ foo: 'baz' });
const qux = new TestObject({ foo: 'qux' });
await reconfigureServer({ maxLimit: 1 });
await Parse.Object.saveAll([baz, qux]);
const obj1 = new TestObject({ foo: 'baz' });
const obj2 = new TestObject({ foo: 'qux' });
await Parse.Object.saveAll([obj1, obj2]);
const query = new Parse.Query(TestObject);
query.limit(2);
const results = await query.find();
equal(results.length, 1);
const result = await query.find();
expect(result.length).toBe(1);
});
it('containedIn object array queries', function (done) {
@@ -1715,6 +1733,16 @@ describe('Parse.Query testing', () => {
});
});
it('order by non-existing string', async () => {
const strings = ['a', 'b', 'c', 'd'];
const makeBoxedNumber = function (num, i) {
return new BoxedNumber({ number: num, string: strings[i] });
};
await Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber));
const results = await new Parse.Query(BoxedNumber).ascending('foo').find();
expect(results.length).toBe(4);
});
it('order by descending number then ascending string', function (done) {
const strings = ['a', 'b', 'c', 'd'];
const makeBoxedNumber = function (num, i) {
+43
View File
@@ -410,6 +410,49 @@ describe('Parse.Relation testing', () => {
});
});
it('or queries with base constraint on relation field', async () => {
const ChildObject = Parse.Object.extend('ChildObject');
const childObjects = [];
for (let i = 0; i < 10; i++) {
childObjects.push(new ChildObject({ x: i }));
}
await Parse.Object.saveAll(childObjects);
const ParentObject = Parse.Object.extend('ParentObject');
const parent = new ParentObject();
parent.set('x', 4);
const relation = parent.relation('toChilds');
relation.add(childObjects[0]);
relation.add(childObjects[1]);
relation.add(childObjects[2]);
const parent2 = new ParentObject();
parent2.set('x', 3);
const relation2 = parent2.relation('toChilds');
relation2.add(childObjects[0]);
relation2.add(childObjects[1]);
relation2.add(childObjects[2]);
const parents = [];
parents.push(parent);
parents.push(parent2);
parents.push(new ParentObject());
await Parse.Object.saveAll(parents);
const query1 = new Parse.Query(ParentObject);
query1.equalTo('x', 4);
const query2 = new Parse.Query(ParentObject);
query2.equalTo('x', 3);
const query = Parse.Query.or(query1, query2);
query.equalTo('toChilds', childObjects[2]);
const list = await query.find();
const objectIds = list.map(item => item.id);
expect(objectIds.indexOf(parent.id)).not.toBe(-1);
expect(objectIds.indexOf(parent2.id)).not.toBe(-1);
equal(list.length, 2, 'There should be 2 results');
});
it('Get query on relation using un-fetched parent object', done => {
// Setup data model
const Wheel = Parse.Object.extend('Wheel');
+1 -1
View File
@@ -142,7 +142,7 @@ describe('Parse Role testing', () => {
return Promise.all(promises);
};
const restExecute = spyOn(RestQuery.prototype, 'execute').and.callThrough();
const restExecute = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough();
let user, auth, getAllRolesSpy;
createTestUser()
+10 -17
View File
@@ -29,27 +29,20 @@ describe('Server Url Checks', () => {
server.close(done);
});
it('validate good server url', done => {
it('validate good server url', async () => {
Parse.serverURL = 'http://localhost:13376';
ParseServer.verifyServerUrl(async result => {
if (!result) {
done.fail('Did not pass valid url');
}
await reconfigureServer();
done();
});
const response = await ParseServer.verifyServerUrl();
expect(response).toBeTrue();
});
it('mark bad server url', done => {
it('mark bad server url', async () => {
spyOn(console, 'warn').and.callFake(() => {});
Parse.serverURL = 'notavalidurl';
ParseServer.verifyServerUrl(async result => {
if (result) {
done.fail('Did not mark invalid url');
}
await reconfigureServer();
done();
});
const response = await ParseServer.verifyServerUrl();
expect(response).not.toBeTrue();
expect(console.warn).toHaveBeenCalledWith(
`\nWARNING, Unable to connect to 'notavalidurl' as the URL is invalid. Cloud code and push notifications may be unavailable!\n`
);
});
xit('handleShutdown, close connection', done => {
@@ -92,7 +85,7 @@ describe('Server Url Checks', () => {
close = true;
},
});
const parseServer = ParseServer.start(newConfiguration);
const parseServer = ParseServer.startApp(newConfiguration);
});
it('does not have unhandled promise rejection in the case of load error', done => {
+56 -9
View File
@@ -2,7 +2,6 @@ const ParseServerRESTController = require('../lib/ParseServerRESTController')
.ParseServerRESTController;
const ParseServer = require('../lib/ParseServer').default;
const Parse = require('parse/node').Parse;
const semver = require('semver');
const TestUtils = require('../lib/TestUtils');
let RESTController;
@@ -130,19 +129,13 @@ describe('ParseServerRESTController', () => {
});
if (
(semver.satisfies(process.env.MONGODB_VERSION, '>=4.0.4') &&
process.env.MONGODB_TOPOLOGY === 'replicaset' &&
process.env.MONGODB_STORAGE_ENGINE === 'wiredTiger') ||
process.env.MONGODB_TOPOLOGY === 'replicaset' ||
process.env.PARSE_SERVER_TEST_DB === 'postgres'
) {
describe('transactions', () => {
beforeEach(async () => {
await TestUtils.destroyAllDataPermanently(true);
if (
semver.satisfies(process.env.MONGODB_VERSION, '>=4.0.4') &&
process.env.MONGODB_TOPOLOGY === 'replicaset' &&
process.env.MONGODB_STORAGE_ENGINE === 'wiredTiger'
) {
if (process.env.MONGODB_TOPOLOGY === 'replicaset') {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI:
@@ -638,4 +631,58 @@ describe('ParseServerRESTController', () => {
expect(sessions[0].get('installationId')).toBe(installationId);
expect(sessions[0].get('sessionToken')).toBe(loggedUser.sessionToken);
});
it('returns a statusId when running jobs', async () => {
Parse.Cloud.job('CloudJob', () => {
return 'Cloud job completed';
});
const res = await RESTController.request(
'POST',
'/jobs/CloudJob',
{},
{ useMasterKey: true, returnStatus: true }
);
const jobStatusId = res._headers['X-Parse-Job-Status-Id'];
expect(jobStatusId).toBeDefined();
const result = await Parse.Cloud.getJobStatus(jobStatusId);
expect(result.id).toBe(jobStatusId);
});
it('returns a statusId when running push notifications', async () => {
const payload = {
data: { alert: 'We return status!' },
where: { deviceType: 'ios' },
};
const res = await RESTController.request('POST', '/push', payload, {
useMasterKey: true,
returnStatus: true,
});
const pushStatusId = res._headers['X-Parse-Push-Status-Id'];
expect(pushStatusId).toBeDefined();
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result.id).toBe(pushStatusId);
});
it('returns a statusId when running batch push notifications', async () => {
const payload = {
data: { alert: 'We return status!' },
where: { deviceType: 'ios' },
};
const res = await RESTController.request('POST', 'batch', {
requests: [{
method: 'POST',
path: '/push',
body: payload,
}],
}, {
useMasterKey: true,
returnStatus: true,
});
const pushStatusId = res[0]._headers['X-Parse-Push-Status-Id'];
expect(pushStatusId).toBeDefined();
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result.id).toBe(pushStatusId);
});
});
+34
View File
@@ -3,8 +3,11 @@
//
'use strict';
const request = require('../lib/request');
function setupTestUsers() {
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
const user1 = new Parse.User();
const user2 = new Parse.User();
const user3 = new Parse.User();
@@ -17,6 +20,10 @@ function setupTestUsers() {
user2.set('password', 'password');
user3.set('password', 'password');
user1.setACL(acl);
user2.setACL(acl);
user3.setACL(acl);
return user1
.signUp()
.then(() => {
@@ -135,4 +142,31 @@ describe('Parse.Session', () => {
fail(err);
});
});
it('cannot edit session with known ID', async () => {
await setupTestUsers();
const [first, second] = await new Parse.Query(Parse.Session).find({ useMasterKey: true });
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'rest',
'X-Parse-Session-Token': second.get('sessionToken'),
'Content-Type': 'application/json',
};
const firstUser = first.get('user').id;
const secondUser = second.get('user').id;
const e = await request({
method: 'PUT',
headers,
url: `http://localhost:8378/1/sessions/${first.id}`,
body: JSON.stringify({
foo: 'bar',
user: { __type: 'Pointer', className: '_User', objectId: secondUser },
}),
}).catch(e => e.data);
expect(e.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
expect(e.error).toBe('Object not found.');
await Parse.Object.fetchAll([first, second], { useMasterKey: true });
expect(first.get('user').id).toBe(firstUser);
expect(second.get('user').id).toBe(secondUser);
});
});
+270 -77
View File
@@ -13,6 +13,30 @@ const passwordCrypto = require('../lib/password');
const Config = require('../lib/Config');
const cryptoUtils = require('../lib/cryptoUtils');
describe('allowExpiredAuthDataToken option', () => {
it('should accept true value', async () => {
await reconfigureServer({ allowExpiredAuthDataToken: true });
expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(true);
});
it('should accept false value', async () => {
await reconfigureServer({ allowExpiredAuthDataToken: false });
expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(false);
});
it('should default false', async () => {
await reconfigureServer({});
expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(false);
});
it('should enforce boolean values', async () => {
const options = [[], 'a', '', 0, 1, {}, 'true', 'false'];
for (const option of options) {
await expectAsync(reconfigureServer({ allowExpiredAuthDataToken: option })).toBeRejected();
}
});
});
describe('Parse.User testing', () => {
it('user sign up class method', async done => {
const user = await Parse.User.signUp('asdf', 'zxcv');
@@ -50,6 +74,36 @@ describe('Parse.User testing', () => {
}
});
it('user login with context', async () => {
let hit = 0;
const context = { foo: 'bar' };
Parse.Cloud.beforeLogin(req => {
expect(req.context).toEqual(context);
hit++;
});
Parse.Cloud.afterLogin(req => {
expect(req.context).toEqual(context);
hit++;
});
await Parse.User.signUp('asdf', 'zxcv');
await request({
method: 'POST',
url: 'http://localhost:8378/1/login',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Cloud-Context': JSON.stringify(context),
'Content-Type': 'application/json',
},
body: {
_method: 'GET',
username: 'asdf',
password: 'zxcv',
},
});
expect(hit).toBe(2);
});
it('user login with non-string username with REST API', async done => {
await Parse.User.signUp('asdf', 'zxcv');
request({
@@ -139,14 +193,13 @@ describe('Parse.User testing', () => {
const ACL = user.getACL();
expect(ACL.getReadAccess(user)).toBe(true);
expect(ACL.getWriteAccess(user)).toBe(true);
expect(ACL.getPublicReadAccess()).toBe(true);
expect(ACL.getPublicReadAccess()).toBe(false);
expect(ACL.getPublicWriteAccess()).toBe(false);
const perms = ACL.permissionsById;
expect(Object.keys(perms).length).toBe(2);
expect(Object.keys(perms).length).toBe(1);
expect(perms[user.id].read).toBe(true);
expect(perms[user.id].write).toBe(true);
expect(perms['*'].read).toBe(true);
expect(perms['*'].write).not.toBe(true);
expect(perms['*']).toBeUndefined();
done();
});
@@ -818,8 +871,8 @@ describe('Parse.User testing', () => {
kevin.set('password', 'mypass');
await kevin.signUp();
const query = new Parse.Query(Parse.User);
const count = await query.count();
equal(count, 2);
const count = await query.find({ useMasterKey: true });
equal(count.length, 2);
done();
});
@@ -1129,7 +1182,7 @@ describe('Parse.User testing', () => {
this.synchronizedExpiration = authData.expiration_date;
return true;
},
getAuthType: function () {
getAuthType() {
return 'facebook';
},
deauthenticate: function () {
@@ -1158,7 +1211,7 @@ describe('Parse.User testing', () => {
synchronizedAuthToken: null,
synchronizedExpiration: null,
authenticate: function (options) {
authenticate(options) {
if (this.shouldError) {
options.error(this, 'An error occurred');
} else if (this.shouldCancel) {
@@ -1167,7 +1220,7 @@ describe('Parse.User testing', () => {
options.success(this, this.authData);
}
},
restoreAuthentication: function (authData) {
restoreAuthentication(authData) {
if (!authData) {
this.synchronizedUserId = null;
this.synchronizedAuthToken = null;
@@ -1179,10 +1232,10 @@ describe('Parse.User testing', () => {
this.synchronizedExpiration = authData.expiration_date;
return true;
},
getAuthType: function () {
getAuthType() {
return 'myoauth';
},
deauthenticate: function () {
deauthenticate() {
this.loggedOut = true;
this.restoreAuthentication(null);
},
@@ -1792,7 +1845,7 @@ describe('Parse.User testing', () => {
});
});
it('should allow login with old authData token', done => {
it('should not allow login with expired authData token since allowExpiredAuthDataToken is set to false by default', async () => {
const provider = {
authData: {
id: '12345',
@@ -1813,22 +1866,12 @@ describe('Parse.User testing', () => {
};
defaultConfiguration.auth.shortLivedAuth.setValidAccessToken('token');
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith('shortLivedAuth', {})
.then(() => {
// Simulate a remotely expired token (like a short lived one)
// In this case, we want success as it was valid once.
// If the client needs an updated one, do lock the user out
defaultConfiguration.auth.shortLivedAuth.setValidAccessToken('otherToken');
return Parse.User._logInWith('shortLivedAuth', {});
})
.then(
() => {
done();
},
err => {
done.fail(err);
}
);
await Parse.User._logInWith('shortLivedAuth', {});
// Simulate a remotely expired token (like a short lived one)
// In this case, we want success as it was valid once.
// If the client needs an updated token, do lock the user out
defaultConfiguration.auth.shortLivedAuth.setValidAccessToken('otherToken');
await expectAsync(Parse.User._logInWith('shortLivedAuth', {})).toBeRejected();
});
it('should allow PUT request with stale auth Data', done => {
@@ -2076,7 +2119,15 @@ describe('Parse.User testing', () => {
});
it("querying for users doesn't get session tokens", done => {
Parse.User.signUp('finn', 'human', { foo: 'bar' })
const user = new Parse.User();
user.set('username', 'finn');
user.set('password', 'human');
user.set('foo', 'bar');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
user
.signUp()
.then(function () {
return Parse.User.logOut();
})
@@ -2085,6 +2136,9 @@ describe('Parse.User testing', () => {
user.set('username', 'jake');
user.set('password', 'dog');
user.set('foo', 'baz');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
return user.signUp();
})
.then(function () {
@@ -2111,7 +2165,14 @@ describe('Parse.User testing', () => {
});
it('querying for users only gets the expected fields', done => {
Parse.User.signUp('finn', 'human', { foo: 'bar' }).then(() => {
const user = new Parse.User();
user.setUsername('finn');
user.setPassword('human');
user.set('foo', 'bar');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
user.signUp().then(() => {
request({
headers: {
'X-Parse-Application-Id': 'test',
@@ -2260,37 +2321,14 @@ describe('Parse.User testing', () => {
});
describe('anonymous users', () => {
beforeEach(() => {
const insensitiveCollisions = [
'abcdefghijklmnop',
'Abcdefghijklmnop',
'ABcdefghijklmnop',
'ABCdefghijklmnop',
'ABCDefghijklmnop',
'ABCDEfghijklmnop',
'ABCDEFghijklmnop',
'ABCDEFGhijklmnop',
'ABCDEFGHijklmnop',
'ABCDEFGHIjklmnop',
'ABCDEFGHIJklmnop',
'ABCDEFGHIJKlmnop',
'ABCDEFGHIJKLmnop',
'ABCDEFGHIJKLMnop',
'ABCDEFGHIJKLMnop',
'ABCDEFGHIJKLMNop',
'ABCDEFGHIJKLMNOp',
'ABCDEFGHIJKLMNOP',
];
// need a bunch of spare random strings per api request
spyOn(cryptoUtils, 'randomString').and.returnValues(...insensitiveCollisions);
});
it('should not fail on case insensitive matches', async () => {
const user1 = await Parse.AnonymousUtils.logIn();
spyOn(cryptoUtils, 'randomString').and.returnValue('abcdefghijklmnop');
const logIn = id => Parse.User.logInWith('anonymous', { authData: { id } });
const user1 = await logIn('test1');
const username1 = user1.get('username');
const user2 = await Parse.AnonymousUtils.logIn();
cryptoUtils.randomString.and.returnValue('ABCDEFGHIJKLMNOp');
const user2 = await logIn('test2');
const username2 = user2.get('username');
expect(username1).not.toBeUndefined();
@@ -2966,6 +3004,7 @@ describe('Parse.User testing', () => {
},
});
})
.then(() => jasmine.timeout())
.then(() => {
expect(emailCalled).toBe(true);
expect(emailOptions).not.toBeUndefined();
@@ -3123,6 +3162,35 @@ describe('Parse.User testing', () => {
.catch(done.fail);
});
it('should return current session with expired expiration date', async () => {
await Parse.User.signUp('buser', 'somepass', null);
const response = await request({
method: 'GET',
url: 'http://localhost:8378/1/classes/_Session',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test',
},
});
const body = response.data;
const id = body.results[0].objectId;
const expiresAt = new Date(new Date().setYear(2015));
await request({
method: 'PUT',
url: 'http://localhost:8378/1/classes/_Session/' + id,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test',
'Content-Type': 'application/json',
},
body: {
expiresAt: { __type: 'Date', iso: expiresAt.toISOString() },
},
});
const session = await Parse.Session.current();
expect(session.get('expiresAt')).toEqual(expiresAt);
});
it('should not create extraneous session tokens', done => {
const config = Config.get(Parse.applicationId);
config.database
@@ -3372,6 +3440,9 @@ describe('Parse.User testing', () => {
password: 'world',
email: 'test@email.com',
});
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
reconfigureServer({
appName: 'unused',
@@ -3448,40 +3519,128 @@ describe('Parse.User testing', () => {
});
});
it('should not allow updates to hidden fields', done => {
it('should not allow updates to hidden fields', async () => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
const user = new Parse.User();
user.set({
username: 'hello',
password: 'world',
email: 'test@email.com',
});
reconfigureServer({
await reconfigureServer({
appName: 'unused',
verifyUserEmails: true,
emailAdapter: emailAdapter,
publicServerURL: 'http://localhost:8378/1',
})
.then(() => {
return user.signUp();
})
.then(() => {
return Parse.User.current().set('_email_verify_token', 'bad').save();
})
.then(() => {
fail('Should not be able to update email verification token');
done();
})
.catch(err => {
expect(err).toBeDefined();
done();
});
});
await user.signUp();
user.set('_email_verify_token', 'bad', { ignoreValidation: true });
await expectAsync(user.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid field name: _email_verify_token.')
);
});
it('should allow updates to fields with maintenanceKey', async () => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
const user = new Parse.User();
user.set({
username: 'hello',
password: 'world',
email: 'test@example.com',
});
await reconfigureServer({
appName: 'unused',
maintenanceKey: 'test2',
verifyUserEmails: true,
emailVerifyTokenValidityDuration: 5,
accountLockout: {
duration: 1,
threshold: 1,
},
emailAdapter: emailAdapter,
publicServerURL: 'http://localhost:8378/1',
});
await user.signUp();
for (let i = 0; i < 2; i++) {
try {
await Parse.User.logIn(user.getEmail(), 'abc');
} catch (e) {
expect(e.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
expect(
e.message === 'Invalid username/password.' ||
e.message ===
'Your account is locked due to multiple failed login attempts. Please try again after 1 minute(s)'
).toBeTrue();
}
}
await Parse.User.requestPasswordReset(user.getEmail());
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'rest',
'X-Parse-Maintenance-Key': 'test2',
'Content-Type': 'application/json',
};
const userMaster = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User`,
json: true,
headers,
}).then(res => res.data.results[0]);
expect(Object.keys(userMaster).sort()).toEqual(
[
'ACL',
'_account_lockout_expires_at',
'_email_verify_token',
'_email_verify_token_expires_at',
'_failed_login_count',
'_perishable_token',
'createdAt',
'email',
'emailVerified',
'objectId',
'updatedAt',
'username',
].sort()
);
const toSet = {
_account_lockout_expires_at: new Date(),
_email_verify_token: 'abc',
_email_verify_token_expires_at: new Date(),
_failed_login_count: 0,
_perishable_token_expires_at: new Date(),
_perishable_token: 'abc',
};
await request({
method: 'PUT',
headers,
url: Parse.serverURL + '/users/' + userMaster.objectId,
json: true,
body: toSet,
}).then(res => res.data);
const update = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User`,
json: true,
headers,
}).then(res => res.data.results[0]);
for (const key in toSet) {
const value = toSet[key];
if (update[key] && update[key].iso) {
expect(update[key].iso).toEqual(value.toISOString());
} else if (value.toISOString) {
expect(update[key]).toEqual(value.toISOString());
} else {
expect(update[key]).toEqual(value);
}
}
});
it('should revoke sessions when setting paswword with masterKey (#3289)', done => {
@@ -4003,6 +4162,12 @@ describe('Parse.User testing', () => {
silent: true,
});
Parse.Cloud.beforeSave(Parse.User, ({ object }) => {
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
object.setACL(acl);
});
const query = new Parse.Query(Parse.User);
query.doesNotExist('foo');
const subscription = await query.subscribe();
@@ -4237,3 +4402,31 @@ describe('login as other user', () => {
done();
});
});
describe('allowClientClassCreation option', () => {
it('should enforce boolean values', async () => {
const options = [[], 'a', '', 0, 1, {}, 'true', 'false'];
for (const option of options) {
await expectAsync(reconfigureServer({ allowClientClassCreation: option })).toBeRejected();
}
});
it('should accept true value', async () => {
await reconfigureServer({ allowClientClassCreation: true });
expect(Config.get(Parse.applicationId).allowClientClassCreation).toBe(true);
});
it('should accept false value', async () => {
await reconfigureServer({ allowClientClassCreation: false });
expect(Config.get(Parse.applicationId).allowClientClassCreation).toBe(false);
});
it('should default false', async () => {
// remove predefined allowClientClassCreation:true on global defaultConfiguration
delete defaultConfiguration.allowClientClassCreation;
await reconfigureServer(defaultConfiguration);
expect(Config.get(Parse.applicationId).allowClientClassCreation).toBe(false);
// Need to set it back to true to avoid other test fails
defaultConfiguration.allowClientClassCreation = true;
});
});
+25 -5
View File
@@ -1677,12 +1677,19 @@ describe('Password Policy: ', () => {
});
it('should not infinitely loop if maxPasswordHistory is 1 (#4918)', async () => {
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'test',
'X-Parse-Maintenance-Key': 'test2',
'Content-Type': 'application/json',
};
const user = new Parse.User();
const query = new Parse.Query(Parse.User);
await reconfigureServer({
appName: 'passwordPolicy',
verifyUserEmails: false,
maintenanceKey: 'test2',
passwordPolicy: {
maxPasswordHistory: 1,
},
@@ -1696,15 +1703,28 @@ describe('Password Policy: ', () => {
user.setPassword('user2');
await user.save();
const result1 = await query.get(user.id, { useMasterKey: true });
expect(result1.get('_password_history').length).toBe(1);
const user1 = await query.get(user.id, { useMasterKey: true });
expect(user1.get('_password_history')).toBeUndefined();
const result1 = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers,
}).then(res => res.data);
expect(result1._password_history.length).toBe(1);
user.setPassword('user3');
await user.save();
const result2 = await query.get(user.id, { useMasterKey: true });
expect(result2.get('_password_history').length).toBe(1);
const result2 = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers,
}).then(res => res.data);
expect(result2._password_history.length).toBe(1);
expect(result1.get('_password_history')).not.toEqual(result2.get('_password_history'));
expect(result1._password_history).not.toEqual(result2._password_history);
});
});
+17 -3
View File
@@ -27,13 +27,13 @@ const baseURI = 'postgres://username:password@localhost:5432/db-name';
const testfile = fs.readFileSync('./Dockerfile').toString();
const dbOptionsTest = {};
dbOptionsTest[
`${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=10`
`${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=12`
] = {
ssl: true,
binary: true,
application_name: 'app_name',
fallback_application_name: 'f_app_name',
poolSize: 10,
max: 12,
};
dbOptionsTest[`${baseURI}?ssl=&binary=aa`] = {
binary: false,
@@ -83,6 +83,20 @@ describe('PostgresConfigParser.getDatabaseOptionsFromURI', () => {
it('sets the poolSize to 10 if the it is not a number', () => {
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=sdf`);
expect(result.poolSize).toEqual(10);
expect(result.max).toEqual(10);
});
it('sets the max to 10 if the it is not a number', () => {
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?&max=sdf`);
expect(result.poolSize).toBeUndefined();
expect(result.max).toEqual(10);
});
it('max should take precedence over poolSize', () => {
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=20&max=12`);
expect(result.poolSize).toBeUndefined();
expect(result.max).toEqual(12);
});
});
+12
View File
@@ -13,6 +13,9 @@ describe('ProtectedFields', function () {
user.setPassword('sekrit');
user.set('email', 'alice@aol.com');
user.set('favoriteColor', 'yellow');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save();
const fetched = await new Parse.Query(Parse.User).get(user.id);
@@ -35,6 +38,9 @@ describe('ProtectedFields', function () {
user.set('timeZone', 'America/Los_Angeles');
user.set('favoriteColor', 'yellow');
user.set('favoriteFood', 'pizza');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save();
const fetched = await new Parse.Query(Parse.User).get(user.id);
@@ -57,6 +63,9 @@ describe('ProtectedFields', function () {
user.set('timeZone', 'America/Los_Angeles');
user.set('favoriteColor', 'yellow');
user.set('favoriteFood', 'pizza');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save();
const fetched = await new Parse.Query(Parse.User).get(user.id);
@@ -108,6 +117,9 @@ describe('ProtectedFields', function () {
user.set('timeZone', 'America/Los_Angeles');
user.set('favoriteColor', 'yellow');
user.set('favoriteFood', 'pizza');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save();
const objA = await new Parse.Object('ClassA').set('foo', 'zzz').set('bar', 'yyy').save();
+4 -6
View File
@@ -26,14 +26,12 @@ const successfulIOS = function (body, installations) {
return Promise.all(promises);
};
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const pushCompleted = async pushId => {
const query = new Parse.Query('_PushStatus');
query.equalTo('objectId', pushId);
let result = await query.first({ useMasterKey: true });
while (!(result && result.get('status') === 'succeeded')) {
await sleep(100);
await jasmine.timeout();
result = await query.first({ useMasterKey: true });
}
};
@@ -562,7 +560,7 @@ describe('PushController', () => {
});
const pushStatusId = await sendPush(payload, {}, config, auth);
// it is enqueued so it can take time
await sleep(1000);
await jasmine.timeout(1000);
Parse.serverURL = 'http://localhost:8378/1'; // GOOD url
const result = await Parse.Push.getPushStatus(pushStatusId);
expect(result).toBeDefined();
@@ -801,7 +799,7 @@ describe('PushController', () => {
});
await Parse.Object.saveAll(installations);
await pushController.sendPush(payload, {}, config, auth);
await sleep(1000);
await jasmine.timeout(1000);
const query = new Parse.Query('_PushStatus');
const results = await query.find({ useMasterKey: true });
expect(results.length).toBe(1);
@@ -856,7 +854,7 @@ describe('PushController', () => {
const config = Config.get(Parse.applicationId);
await Parse.Object.saveAll(installations);
await pushController.sendPush(payload, {}, config, auth);
await sleep(1000);
await jasmine.timeout(1000);
const query = new Parse.Query('_PushStatus');
const results = await query.find({ useMasterKey: true });
expect(results.length).toBe(1);
+52
View File
@@ -125,6 +125,35 @@ describe('matchesQuery', function () {
expect(matchesQuery(obj, q)).toBe(false);
});
it('matches queries with eq constraint', function () {
const obj = {
objectId: 'Person2',
score: 12,
name: 'Tom',
};
const q1 = {
objectId: {
$eq: 'Person2',
},
};
const q2 = {
score: {
$eq: 12,
},
};
const q3 = {
name: {
$eq: 'Tom',
},
};
expect(matchesQuery(obj, q1)).toBe(true);
expect(matchesQuery(obj, q2)).toBe(true);
expect(matchesQuery(obj, q3)).toBe(true);
});
it('matches on equality queries', function () {
const day = new Date();
const location = new Parse.GeoPoint({
@@ -583,6 +612,29 @@ describe('matchesQuery', function () {
expect(matchesQuery(message, q)).toBe(false);
});
it('should support containedIn with array of pointers', () => {
const message = {
id: new Id('Message', 'O2'),
profiles: [pointer('Profile', 'yeahaw'), pointer('Profile', 'yes')],
};
let q = new Parse.Query('Message');
q.containedIn('profiles', [
Parse.Object.fromJSON({ className: 'Profile', objectId: 'no' }),
Parse.Object.fromJSON({ className: 'Profile', objectId: 'yes' }),
]);
expect(matchesQuery(message, q)).toBe(true);
q = new Parse.Query('Message');
q.containedIn('profiles', [
Parse.Object.fromJSON({ className: 'Profile', objectId: 'no' }),
Parse.Object.fromJSON({ className: 'Profile', objectId: 'nope' }),
]);
expect(matchesQuery(message, q)).toBe(false);
});
it('should support notContainedIn with pointers', () => {
let message = {
id: new Id('Message', 'O1'),
+519
View File
@@ -0,0 +1,519 @@
const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default;
describe('rate limit', () => {
it('can limit cloud functions', async () => {
Parse.Cloud.define('test', () => 'Abc');
await reconfigureServer({
rateLimit: [
{
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const response1 = await Parse.Cloud.run('test');
expect(response1).toBe('Abc');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can limit cloud functions with user session token', async () => {
await Parse.User.signUp('myUser', 'password');
Parse.Cloud.define('test', () => 'Abc');
await reconfigureServer({
rateLimit: [
{
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const response1 = await Parse.Cloud.run('test');
expect(response1).toBe('Abc');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can add global limit', async () => {
Parse.Cloud.define('test', () => 'Abc');
await reconfigureServer({
rateLimit: {
requestPath: '*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
const response1 = await Parse.Cloud.run('test');
expect(response1).toBe('Abc');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
await expectAsync(new Parse.Object('Test').save()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can limit cloud with validator', async () => {
Parse.Cloud.define('test', () => 'Abc', {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
const response1 = await Parse.Cloud.run('test');
expect(response1).toBe('Abc');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can skip with masterKey', async () => {
Parse.Cloud.define('test', () => 'Abc');
await reconfigureServer({
rateLimit: [
{
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const response1 = await Parse.Cloud.run('test', null, { useMasterKey: true });
expect(response1).toBe('Abc');
const response2 = await Parse.Cloud.run('test', null, { useMasterKey: true });
expect(response2).toBe('Abc');
});
it('should run with masterKey', async () => {
Parse.Cloud.define('test', () => 'Abc');
await reconfigureServer({
rateLimit: [
{
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
includeMasterKey: true,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const response1 = await Parse.Cloud.run('test', null, { useMasterKey: true });
expect(response1).toBe('Abc');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can limit saving objects', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/classes/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const obj = new Parse.Object('Test');
await obj.save();
await expectAsync(obj.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can set method to post', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/classes/*',
requestTimeWindow: 10000,
requestCount: 1,
requestMethods: 'POST',
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const obj = new Parse.Object('Test');
await obj.save();
await obj.save();
const obj2 = new Parse.Object('Test');
await expectAsync(obj2.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can use a validator for post', async () => {
Parse.Cloud.beforeSave('Test', () => {}, {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
const obj = new Parse.Object('Test');
await obj.save();
await expectAsync(obj.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can use a validator for file', async () => {
Parse.Cloud.beforeSave(Parse.File, () => {}, {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
const file = new Parse.File('yolo.txt', [1, 2, 3], 'text/plain');
await file.save();
const file2 = new Parse.File('yolo.txt', [1, 2, 3], 'text/plain');
await expectAsync(file2.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can set method to get', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/classes/Test',
requestTimeWindow: 10000,
requestCount: 1,
requestMethods: 'GET',
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const obj = new Parse.Object('Test');
await obj.save();
await obj.save();
await new Parse.Query('Test').first();
await expectAsync(new Parse.Query('Test').first()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can use a validator', async () => {
await reconfigureServer({ silent: false });
Parse.Cloud.beforeFind('TestObject', () => {}, {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
const obj = new Parse.Object('TestObject');
await obj.save();
await obj.save();
await new Parse.Query('TestObject').first();
await expectAsync(new Parse.Query('TestObject').first()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
await expectAsync(new Parse.Query('TestObject').get('abc')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can set method to delete', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/classes/Test/*',
requestTimeWindow: 10000,
requestCount: 1,
requestMethods: 'DELETE',
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
const obj = new Parse.Object('Test');
await obj.save();
await obj.destroy();
await expectAsync(obj.destroy()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can set beforeDelete', async () => {
const obj = new Parse.Object('TestDelete');
await obj.save();
Parse.Cloud.beforeDelete('TestDelete', () => {}, {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
await obj.destroy();
await expectAsync(obj.destroy()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can set beforeLogin', async () => {
Parse.Cloud.beforeLogin(() => {}, {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
});
await Parse.User.signUp('myUser', 'password');
await Parse.User.logIn('myUser', 'password');
await expectAsync(Parse.User.logIn('myUser', 'password')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
it('can define limits via rateLimit and define', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 100,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
},
],
});
Parse.Cloud.define('test', () => 'Abc', {
rateLimit: {
requestTimeWindow: 10000,
requestCount: 1,
includeInternalRequests: true,
},
});
const response1 = await Parse.Cloud.run('test');
expect(response1).toBe('Abc');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests.')
);
});
it('does not limit internal calls', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
},
],
});
Parse.Cloud.define('test1', () => 'Abc');
Parse.Cloud.define('test2', async () => {
await Parse.Cloud.run('test1');
await Parse.Cloud.run('test1');
});
await Parse.Cloud.run('test2');
});
describe('zone', () => {
const middlewares = require('../lib/middlewares');
it('can use global zone', async () => {
await reconfigureServer({
rateLimit: {
requestPath: '*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
zone: Parse.Server.RateLimitZone.global,
},
});
const fakeReq = {
originalUrl: 'http://example.com/parse/',
url: 'http://example.com/',
body: {
_ApplicationId: 'test',
},
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
get: key => {
return fakeReq.headers[key];
},
};
fakeReq.ip = '127.0.0.1';
let fakeRes = jasmine.createSpyObj('fakeRes', ['end', 'status', 'setHeader', 'json']);
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
fakeReq.ip = '127.0.0.2';
fakeRes = jasmine.createSpyObj('fakeRes', ['end', 'status', 'setHeader']);
let resolvingPromise;
const promise = new Promise(resolve => {
resolvingPromise = resolve;
});
fakeRes.json = jasmine.createSpy('json').and.callFake(resolvingPromise);
middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
throw 'Should not call next';
});
await promise;
expect(fakeRes.status).toHaveBeenCalledWith(429);
expect(fakeRes.json).toHaveBeenCalledWith({
code: Parse.Error.CONNECTION_FAILED,
error: 'Too many requests',
});
});
it('can use session zone', async () => {
await reconfigureServer({
rateLimit: {
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
zone: Parse.Server.RateLimitZone.session,
},
});
Parse.Cloud.define('test', () => 'Abc');
await Parse.User.signUp('username', 'password');
await Parse.Cloud.run('test');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
await Parse.User.logIn('username', 'password');
await Parse.Cloud.run('test');
});
it('can use user zone', async () => {
await reconfigureServer({
rateLimit: {
requestPath: '/functions/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
zone: Parse.Server.RateLimitZone.user,
},
});
Parse.Cloud.define('test', () => 'Abc');
await Parse.User.signUp('username', 'password');
await Parse.Cloud.run('test');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
await Parse.User.logIn('username', 'password');
await expectAsync(Parse.Cloud.run('test')).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
});
});
it('can validate rateLimit', async () => {
const Config = require('../lib/Config');
const validateRateLimit = ({ rateLimit }) => Config.validateRateLimit(rateLimit);
expect(() =>
validateRateLimit({ rateLimit: 'a', requestTimeWindow: 1000, requestCount: 3 })
).toThrow('rateLimit must be an array or object');
expect(() => validateRateLimit({ rateLimit: ['a'] })).toThrow(
'rateLimit must be an array of objects'
);
expect(() => validateRateLimit({ rateLimit: [{ requestPath: [] }] })).toThrow(
'rateLimit.requestPath must be a string'
);
expect(() =>
validateRateLimit({ rateLimit: [{ requestTimeWindow: [], requestPath: 'a' }] })
).toThrow('rateLimit.requestTimeWindow must be a number');
expect(() =>
validateRateLimit({
rateLimit: [{ requestPath: 'a', requestTimeWindow: 1000, requestCount: 3, zone: 'abc' }],
})
).toThrow('rateLimit.zone must be one of global, session, user, or ip');
expect(() =>
validateRateLimit({
rateLimit: [
{
includeInternalRequests: [],
requestTimeWindow: 1000,
requestCount: 3,
requestPath: 'a',
},
],
})
).toThrow('rateLimit.includeInternalRequests must be a boolean');
expect(() =>
validateRateLimit({
rateLimit: [{ requestCount: [], requestTimeWindow: 1000, requestPath: 'a' }],
})
).toThrow('rateLimit.requestCount must be a number');
expect(() =>
validateRateLimit({
rateLimit: [
{ errorResponseMessage: [], requestTimeWindow: 1000, requestCount: 3, requestPath: 'a' },
],
})
).toThrow('rateLimit.errorResponseMessage must be a string');
expect(() =>
validateRateLimit({ rateLimit: [{ requestCount: 3, requestPath: 'abc' }] })
).toThrow('rateLimit.requestTimeWindow must be defined');
expect(() =>
validateRateLimit({ rateLimit: [{ requestTimeWindow: 3, requestPath: 'abc' }] })
).toThrow('rateLimit.requestCount must be defined');
expect(() =>
validateRateLimit({ rateLimit: [{ requestTimeWindow: 3, requestCount: 'abc' }] })
).toThrow('rateLimit.requestPath must be defined');
await expectAsync(
reconfigureServer({
rateLimit: [{ requestTimeWindow: 3, requestCount: 1, path: 'abc', requestPath: 'a' }],
})
).toBeRejectedWith(`Invalid rate limit option "path"`);
});
describe_only(() => {
return process.env.PARSE_SERVER_TEST_CACHE === 'redis';
})('with RedisCache', function () {
it('does work with cache', async () => {
await reconfigureServer({
rateLimit: [
{
requestPath: '/classes/*',
requestTimeWindow: 10000,
requestCount: 1,
errorResponseMessage: 'Too many requests',
includeInternalRequests: true,
redisUrl: 'redis://localhost:6379',
},
],
});
const obj = new Parse.Object('Test');
await obj.save();
await expectAsync(obj.save()).toBeRejectedWith(
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
);
const cache = new RedisCacheAdapter();
await cache.connect();
const value = await cache.get('rl:127.0.0.1');
expect(value).toEqual(2);
const ttl = await cache.client.ttl('rl:127.0.0.1');
expect(ttl).toEqual(10);
});
});
});
+2 -2
View File
@@ -625,7 +625,7 @@ describe_only_db('mongo')('Read preference option', () => {
spyOn(Collection.prototype, 'aggregate').and.callThrough();
// Query
const query = new Parse.Query('MyObject');
const results = await query.aggregate([{ match: { boolKey: false } }]);
const results = await query.aggregate([{ $match: { boolKey: false } }]);
// Validate
expect(results.length).toBe(1);
let readPreference = null;
@@ -678,7 +678,7 @@ describe_only_db('mongo')('Read preference option', () => {
// Query
const query = new Parse.Query('MyObject');
query.readPreference('SECONDARY');
const results = await query.aggregate([{ match: { boolKey: false } }]);
const results = await query.aggregate([{ $match: { boolKey: false } }]);
// Validate
expect(results.length).toBe(1);
let readPreference = null;
+29 -14
View File
@@ -19,23 +19,22 @@ describe_only(() => {
beforeEach(async () => {
cache = new RedisCacheAdapter(null, 100);
await cache.connect();
await cache.clear();
});
it('should get/set/clear', done => {
it('should get/set/clear', async () => {
const cacheNaN = new RedisCacheAdapter({
ttl: NaN,
});
cacheNaN
.put(KEY, VALUE)
.then(() => cacheNaN.get(KEY))
.then(value => expect(value).toEqual(VALUE))
.then(() => cacheNaN.clear())
.then(() => cacheNaN.get(KEY))
.then(value => expect(value).toEqual(null))
.then(() => cacheNaN.clear())
.then(done);
await cacheNaN.connect();
await cacheNaN.put(KEY, VALUE);
let value = await cacheNaN.get(KEY);
expect(value).toEqual(VALUE);
await cacheNaN.clear();
value = await cacheNaN.get(KEY);
expect(value).toEqual(null);
await cacheNaN.clear();
});
it('should expire after ttl', done => {
@@ -100,7 +99,7 @@ describe_only(() => {
it('handleShutdown, close connection', async () => {
await cache.handleShutdown();
setTimeout(() => {
expect(cache.client.connected).toBe(false);
expect(cache.client.isOpen).toBe(false);
}, 0);
});
});
@@ -122,8 +121,9 @@ describe_only(() => {
return Object.keys(cache.queue.queue).length;
}
it('it should clear completed operations from queue', done => {
it('it should clear completed operations from queue', async done => {
const cache = new RedisCacheAdapter({ ttl: NaN });
await cache.connect();
// execute a bunch of operations in sequence
let promise = Promise.resolve();
@@ -144,8 +144,9 @@ describe_only(() => {
promise.then(() => expect(getQueueCount(cache)).toEqual(0)).then(done);
});
it('it should count per key chained operations correctly', done => {
it('it should count per key chained operations correctly', async done => {
const cache = new RedisCacheAdapter({ ttl: NaN });
await cache.connect();
let key1Promise = Promise.resolve();
let key2Promise = Promise.resolve();
@@ -166,4 +167,18 @@ describe_only(() => {
.then(() => expect(getQueueCount(cache)).toEqual(0))
.then(done);
});
it('should start and connect cache adapter', async () => {
const server = await reconfigureServer({
cacheAdapter: {
module: `${__dirname.replace('/spec', '')}/lib/Adapters/Cache/RedisCacheAdapter`,
options: {
url: 'redis://127.0.0.1:6379/1',
},
},
});
const symbol = Object.getOwnPropertySymbols(server.config.cacheController);
const client = server.config.cacheController[symbol[0]].client;
expect(client.isOpen).toBeTrue();
});
});
+4 -2
View File
@@ -15,7 +15,8 @@ describe('RedisPubSub', function () {
});
const redis = require('redis');
expect(redis.createClient).toHaveBeenCalledWith('redisAddress', {
expect(redis.createClient).toHaveBeenCalledWith({
url: 'redisAddress',
socket_keepalive: true,
no_ready_check: true,
});
@@ -28,7 +29,8 @@ describe('RedisPubSub', function () {
});
const redis = require('redis');
expect(redis.createClient).toHaveBeenCalledWith('redisAddress', {
expect(redis.createClient).toHaveBeenCalledWith({
url: 'redisAddress',
socket_keepalive: true,
no_ready_check: true,
});
+25 -5
View File
@@ -19,6 +19,7 @@ const publicServerURL = 'http://localhost:8378/1';
describe('Regex Vulnerabilities', function () {
beforeEach(async function () {
await reconfigureServer({
maintenanceKey: 'test2',
verifyUserEmails: true,
emailAdapter,
appName,
@@ -98,11 +99,20 @@ describe('Regex Vulnerabilities', function () {
it('should work with plain token', async function () {
expect(this.user.get('emailVerified')).toEqual(false);
const current = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User/${this.user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'test',
'X-Parse-Maintenance-Key': 'test2',
'Content-Type': 'application/json',
},
}).then(res => res.data);
// It should work
await request({
url: `${serverURL}/apps/test/verify_email?username=someemail@somedomain.com&token=${this.user.get(
'_email_verify_token'
)}`,
url: `${serverURL}/apps/test/verify_email?username=someemail@somedomain.com&token=${current._email_verify_token}`,
method: 'GET',
});
await this.user.fetch({ useMasterKey: true });
@@ -164,8 +174,18 @@ describe('Regex Vulnerabilities', function () {
email: 'someemail@somedomain.com',
}),
});
await this.user.fetch({ useMasterKey: true });
const token = this.user.get('_perishable_token');
const current = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User/${this.user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'test',
'X-Parse-Maintenance-Key': 'test2',
'Content-Type': 'application/json',
},
}).then(res => res.data);
const token = current._perishable_token;
const passwordResetResponse = await request({
url: `${serverURL}/apps/test/request_password_reset?username=someemail@somedomain.com&token=${token}`,
method: 'GET',
+98 -21
View File
@@ -96,6 +96,7 @@ describe('rest query', () => {
let user = {
username: 'aUsername',
password: 'aPassword',
ACL: { '*': { read: true } },
};
const activity = {
type: 'comment',
@@ -191,6 +192,79 @@ describe('rest query', () => {
expect(result.results.length).toEqual(0);
});
it('query internal field', async () => {
const internalFields = [
'_email_verify_token',
'_perishable_token',
'_tombstone',
'_email_verify_token_expires_at',
'_failed_login_count',
'_account_lockout_expires_at',
'_password_changed_at',
'_password_history',
];
await Promise.all([
...internalFields.map(field =>
expectAsync(new Parse.Query(Parse.User).exists(field).find()).toBeRejectedWith(
new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${field}`)
)
),
...internalFields.map(field =>
new Parse.Query(Parse.User).exists(field).find({ useMasterKey: true })
),
]);
});
it('query protected field', async () => {
const user = new Parse.User();
user.setUsername('username1');
user.setPassword('password');
await user.signUp();
const config = Config.get(Parse.applicationId);
const obj = new Parse.Object('Test');
obj.set('owner', user);
obj.set('test', 'test');
obj.set('zip', 1234);
await obj.save();
const schema = await config.database.loadSchema();
await schema.updateClass(
'Test',
{},
{
get: { '*': true },
find: { '*': true },
protectedFields: { [user.id]: ['zip'] },
}
);
await Promise.all([
new Parse.Query('Test').exists('test').find(),
expectAsync(new Parse.Query('Test').exists('zip').find()).toBeRejectedWith(
new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
'This user is not allowed to query zip on class Test'
)
),
]);
});
it('query protected field with matchesQuery', async () => {
const user = new Parse.User();
user.setUsername('username1');
user.setPassword('password');
await user.signUp();
const test = new Parse.Object('TestObject', { user });
await test.save();
const subQuery = new Parse.Query(Parse.User);
subQuery.exists('_perishable_token');
await expectAsync(
new Parse.Query('TestObject').matchesQuery('user', subQuery).find()
).toBeRejectedWith(
new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid key name: _perishable_token')
);
});
it('query with wrongly encoded parameter', done => {
rest
.create(config, nobody, 'TestParameterEncode', { foo: 'bar' })
@@ -325,15 +399,16 @@ describe('RestQuery.each', () => {
}
const config = Config.get('test');
await Parse.Object.saveAll(objects);
const query = new RestQuery(
const query = await RestQuery({
method: RestQuery.Method.find,
config,
auth.master(config),
'Object',
{ value: { $gt: 2 } },
{ limit: 2 }
);
auth: auth.master(config),
className: 'Object',
restWhere: { value: { $gt: 2 } },
restOptions: { limit: 2 },
});
const spy = spyOn(query, 'execute').and.callThrough();
const classSpy = spyOn(RestQuery.prototype, 'execute').and.callThrough();
const classSpy = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough();
const results = [];
await query.each(result => {
expect(result.value).toBeGreaterThan(2);
@@ -364,34 +439,37 @@ describe('RestQuery.each', () => {
* Two queries needed since objectId are sorted and we can't know which one
* going to be the first and then skip by the $gt added by each
*/
const queryOne = new RestQuery(
const queryOne = await RestQuery({
method: RestQuery.Method.get,
config,
auth.master(config),
'Letter',
{
auth: auth.master(config),
className: 'Letter',
restWhere: {
numbers: {
__type: 'Pointer',
className: 'Number',
objectId: object1.id,
},
},
{ limit: 1 }
);
const queryTwo = new RestQuery(
restOptions: { limit: 1 },
});
const queryTwo = await RestQuery({
method: RestQuery.Method.get,
config,
auth.master(config),
'Letter',
{
auth: auth.master(config),
className: 'Letter',
restWhere: {
numbers: {
__type: 'Pointer',
className: 'Number',
objectId: object2.id,
},
},
{ limit: 1 }
);
restOptions: { limit: 1 },
});
const classSpy = spyOn(RestQuery.prototype, 'execute').and.callThrough();
const classSpy = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough();
const resultsOne = [];
const resultsTwo = [];
await queryOne.each(result => {
@@ -448,7 +526,6 @@ describe('RestQuery.each', () => {
'createdAt',
'initialToRemove',
'objectId',
'updatedAt',
]);
});
});
+54
View File
@@ -204,4 +204,58 @@ describe('Schema Performance', function () {
);
expect(getAllSpy.calls.count()).toBe(2);
});
it('does reload with schemaCacheTtl', async () => {
const databaseURI =
process.env.PARSE_SERVER_TEST_DB === 'postgres'
? process.env.PARSE_SERVER_TEST_DATABASE_URI
: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase';
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
silent: false,
databaseOptions: { schemaCacheTtl: 1000 },
});
const SchemaController = require('../lib/Controllers/SchemaController').SchemaController;
const spy = spyOn(SchemaController.prototype, 'reloadData').and.callThrough();
Object.defineProperty(spy, 'reloadCalls', {
get: () => spy.calls.all().filter(call => call.args[0].clearCache).length,
});
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
spy.calls.reset();
object.set('foo', 'bar');
await object.save();
expect(spy.reloadCalls).toBe(0);
await new Promise(resolve => setTimeout(resolve, 1100));
object.set('foo', 'bar');
await object.save();
expect(spy.reloadCalls).toBe(1);
});
it('cannot set invalid databaseOptions', async () => {
const expectError = async (key, value, expected) =>
expectAsync(
reconfigureServer({ databaseAdapter: undefined, databaseOptions: { [key]: value } })
).toBeRejectedWith(`databaseOptions.${key} must be a ${expected}`);
for (const databaseOptions of [[], 0, 'string']) {
await expectAsync(
reconfigureServer({ databaseAdapter: undefined, databaseOptions })
).toBeRejectedWith(`databaseOptions must be an object`);
}
for (const value of [null, 0, 'string', {}, []]) {
await expectError('enableSchemaHooks', value, 'boolean');
}
for (const value of [null, false, 'string', {}, []]) {
await expectError('schemaCacheTtl', value, 'number');
}
});
});
+28
View File
@@ -337,5 +337,33 @@ describe('Security Check', () => {
expect(logSpy.calls.all()[0].args[0]).toContain(title);
}
});
it('does update featuresRouter', async () => {
let response = await request({
url: 'http://localhost:8378/1/serverInfo',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Master-Key': 'test',
},
});
expect(response.data.features.settings.securityCheck).toBeTrue();
await reconfigureServer({
security: {
enableCheck: false,
},
});
response = await request({
url: 'http://localhost:8378/1/serverInfo',
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'X-Parse-Master-Key': 'test',
},
});
expect(response.data.features.settings.securityCheck).toBeFalse();
});
});
});
+1 -1
View File
@@ -47,7 +47,7 @@ describe('SessionTokenCache', function () {
sessionTokenCache.getUserId('sessionToken').then(userIdFromCache => {
expect(userIdFromCache).toBe('userId');
expect(sessionTokenCache.cache.length).toBe(1);
expect(sessionTokenCache.cache.size).toBe(1);
done();
});
});
+50 -29
View File
@@ -1,55 +1,76 @@
const UserController = require('../lib/Controllers/UserController').UserController;
const emailAdapter = require('./support/MockEmailAdapter');
const Config = require('../lib/Config');
const Auth = require('../lib/Auth');
describe('UserController', () => {
const user = {
_email_verify_token: 'testToken',
username: 'testUser',
email: 'test@example.com',
};
describe('sendVerificationEmail', () => {
describe('parseFrameURL not provided', () => {
it('uses publicServerURL', async done => {
it('uses publicServerURL', async () => {
await reconfigureServer({
publicServerURL: 'http://www.example.com',
customPages: {
parseFrameURL: undefined,
},
});
emailAdapter.sendVerificationEmail = options => {
expect(options.link).toEqual(
'http://www.example.com/apps/test/verify_email?token=testToken&username=testUser'
);
emailAdapter.sendVerificationEmail = () => Promise.resolve();
done();
};
const userController = new UserController(emailAdapter, 'test', {
verifyUserEmails: true,
emailAdapter,
appName: 'test',
});
userController.sendVerificationEmail(user);
let emailOptions;
emailAdapter.sendVerificationEmail = options => {
emailOptions = options;
return Promise.resolve();
};
const username = 'verificationUser';
const user = new Parse.User();
user.setUsername(username);
user.setPassword('pass');
user.setEmail('verification@example.com');
await user.signUp();
const config = Config.get('test');
const rawUser = await config.database.find('_User', { username }, {}, Auth.maintenance(config));
const rawUsername = rawUser[0].username;
const rawToken = rawUser[0]._email_verify_token;
expect(rawToken).toBeDefined();
expect(rawUsername).toBe(username);
expect(emailOptions.link).toEqual(`http://www.example.com/apps/test/verify_email?token=${rawToken}&username=${username}`);
});
});
describe('parseFrameURL provided', () => {
it('uses parseFrameURL and includes the destination in the link parameter', async done => {
it('uses parseFrameURL and includes the destination in the link parameter', async () => {
await reconfigureServer({
publicServerURL: 'http://www.example.com',
customPages: {
parseFrameURL: 'http://someother.example.com/handle-parse-iframe',
},
});
emailAdapter.sendVerificationEmail = options => {
expect(options.link).toEqual(
'http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=testToken&username=testUser'
);
emailAdapter.sendVerificationEmail = () => Promise.resolve();
done();
};
const userController = new UserController(emailAdapter, 'test', {
verifyUserEmails: true,
emailAdapter,
appName: 'test',
});
userController.sendVerificationEmail(user);
let emailOptions;
emailAdapter.sendVerificationEmail = options => {
emailOptions = options;
return Promise.resolve();
};
const username = 'verificationUser';
const user = new Parse.User();
user.setUsername(username);
user.setPassword('pass');
user.setEmail('verification@example.com');
await user.signUp();
const config = Config.get('test');
const rawUser = await config.database.find('_User', { username }, {}, Auth.maintenance(config));
const rawUsername = rawUser[0].username;
const rawToken = rawUser[0]._email_verify_token;
expect(rawToken).toBeDefined();
expect(rawUsername).toBe(username);
expect(emailOptions.link).toEqual(`http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=${rawToken}&username=${username}`);
});
});
});
+3 -1
View File
@@ -16,7 +16,9 @@ describe('Personally Identifiable Information', () => {
await reconfigureServer();
user = await Parse.User.signUp('tester', 'abc');
user = await Parse.User.logIn(user.get('username'), 'abc');
await user.set('email', EMAIL).set('zip', ZIP).set('ssn', SSN).save();
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
await user.set('email', EMAIL).set('zip', ZIP).set('ssn', SSN).setACL(acl).save();
done();
});
+155 -49
View File
@@ -51,6 +51,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
user.setUsername('zxcv');
user.setEmail('testIfEnabled@parse.com');
await user.signUp();
await jasmine.timeout();
expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled();
user.fetch().then(() => {
expect(user.get('emailVerified')).toEqual(false);
@@ -137,6 +138,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
spyOn(emailAdapter, 'sendVerificationEmail').and.callFake(options => {
expect(options.link).not.toBeNull();
expect(options.link).not.toMatch(/token=undefined/);
expect(options.link).not.toMatch(/username=undefined/);
Promise.resolve();
});
const user = new Parse.User();
@@ -183,6 +185,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
user.setUsername('zxcv');
user.set('email', 'testSendSimpleAdapter@parse.com');
await user.signUp();
await jasmine.timeout();
expect(calls).toBe(1);
user
.fetch()
@@ -242,8 +245,67 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
});
});
it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => {
it('prevents user from signup and login if email is not verified and preventLoginWithUnverifiedEmail is set to function returning true', async () => {
await reconfigureServer({
appName: 'test',
publicServerURL: 'http://localhost:1337/1',
verifyUserEmails: async () => true,
preventLoginWithUnverifiedEmail: async () => true,
preventSignupWithUnverifiedEmail: true,
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
});
const user = new Parse.User();
user.setPassword('asdf');
user.setUsername('zxcv');
user.set('email', 'testInvalidConfig@parse.com');
const signupRes = await user.signUp(null).catch(e => e);
expect(signupRes.message).toEqual('User email is not verified.');
const loginRes = await Parse.User.logIn('zxcv', 'asdf').catch(e => e);
expect(loginRes.message).toEqual('User email is not verified.');
});
it('provides function arguments in verifyUserEmails on login', async () => {
const user = new Parse.User();
user.setUsername('user');
user.setPassword('pass');
user.set('email', 'test@example.com');
await user.signUp();
const verifyUserEmails = {
method: async (params) => {
expect(params.object).toBeInstanceOf(Parse.User);
expect(params.ip).toBeDefined();
expect(params.master).toBeDefined();
expect(params.installationId).toBeDefined();
return true;
},
};
const verifyUserEmailsSpy = spyOn(verifyUserEmails, 'method').and.callThrough();
await reconfigureServer({
appName: 'test',
publicServerURL: 'http://localhost:1337/1',
verifyUserEmails: verifyUserEmails.method,
preventLoginWithUnverifiedEmail: verifyUserEmails.method,
preventSignupWithUnverifiedEmail: true,
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
});
const res = await Parse.User.logIn('user', 'pass').catch(e => e);
expect(res.code).toBe(205);
expect(verifyUserEmailsSpy).toHaveBeenCalledTimes(2);
});
it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', async () => {
let sendEmailOptions;
const emailAdapter = {
sendVerificationEmail: options => {
@@ -252,59 +314,33 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
reconfigureServer({
await reconfigureServer({
appName: 'emailing app',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
emailAdapter: emailAdapter,
publicServerURL: 'http://localhost:8378/1',
})
.then(() => {
user.setPassword('other-password');
user.setUsername('user');
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => {
expect(sendEmailOptions).not.toBeUndefined();
request({
url: sendEmailOptions.link,
followRedirects: false,
}).then(response => {
expect(response.status).toEqual(302);
expect(response.text).toEqual(
'Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user'
);
user
.fetch()
.then(
() => {
expect(user.get('emailVerified')).toEqual(true);
Parse.User.logIn('user', 'other-password').then(
user => {
expect(typeof user).toBe('object');
expect(user.get('emailVerified')).toBe(true);
done();
},
() => {
fail('login should have succeeded');
done();
}
);
},
err => {
jfail(err);
fail('this should not fail');
done();
}
)
.catch(err => {
jfail(err);
done();
});
});
});
});
let user = new Parse.User();
user.setPassword('other-password');
user.setUsername('user');
user.set('email', 'user@example.com');
await user.signUp();
await jasmine.timeout();
expect(sendEmailOptions).not.toBeUndefined();
const response = await request({
url: sendEmailOptions.link,
followRedirects: false,
});
expect(response.status).toEqual(302);
expect(response.text).toEqual(
'Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user'
);
user = await new Parse.Query(Parse.User).first({ useMasterKey: true });
expect(user.get('emailVerified')).toEqual(true);
user = await Parse.User.logIn('user', 'other-password');
expect(typeof user).toBe('object');
expect(user.get('emailVerified')).toBe(true);
});
it('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => {
@@ -345,6 +381,35 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
});
});
it('does not allow signup with preventSignupWithUnverified', async () => {
let sendEmailOptions;
const emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
await reconfigureServer({
appName: 'test',
publicServerURL: 'http://localhost:1337/1',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
preventSignupWithUnverifiedEmail: true,
emailAdapter,
});
const newUser = new Parse.User();
newUser.setPassword('asdf');
newUser.setUsername('zxcv');
newUser.set('email', 'test@example.com');
await expectAsync(newUser.signUp()).toBeRejectedWith(
new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.')
);
const user = await new Parse.Query(Parse.User).first({ useMasterKey: true });
expect(user).toBeDefined();
expect(sendEmailOptions).toBeDefined();
});
it('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => {
reconfigureServer({
appName: undefined,
@@ -573,6 +638,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
user.setUsername('zxcv');
user.set('email', 'user@parse.com');
await user.signUp();
await jasmine.timeout();
expect(emailSent).toBe(true);
done();
});
@@ -600,6 +666,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
user.set('email', 'user@parse.com');
return user.signUp();
})
.then(() => jasmine.timeout())
.then(() => {
expect(sendEmailOptions).not.toBeUndefined();
request({
@@ -1082,4 +1149,43 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
done();
});
});
it('should throw on an invalid reset password', async () => {
await reconfigureServer({
appName: 'coolapp',
publicServerURL: 'http://localhost:1337/1',
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
passwordPolicy: {
resetPasswordSuccessOnInvalidEmail: false,
},
});
await expectAsync(Parse.User.requestPasswordReset('test@example.com')).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'A user with that email does not exist.')
);
});
it('validate resetPasswordSuccessonInvalidEmail', async () => {
const invalidValues = [[], {}, 1, 'string'];
for (const value of invalidValues) {
await expectAsync(
reconfigureServer({
appName: 'coolapp',
publicServerURL: 'http://localhost:1337/1',
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
passwordPolicy: {
resetPasswordSuccessOnInvalidEmail: value,
},
})
).toBeRejectedWith('resetPasswordSuccessOnInvalidEmail must be a boolean value');
}
});
});
+96 -23
View File
@@ -353,8 +353,9 @@ describe('Verify User Password', () => {
done();
});
});
it('fails to verify password when preventLoginWithUnverifiedEmail is set to true REST API', done => {
reconfigureServer({
it('fails to verify password when preventLoginWithUnverifiedEmail is set to true REST API', async () => {
await reconfigureServer({
publicServerURL: 'http://localhost:8378/',
appName: 'emailVerify',
verifyUserEmails: true,
@@ -364,28 +365,21 @@ describe('Verify User Password', () => {
apiKey: 'k',
domain: 'd',
}),
})
.then(() => {
const user = new Parse.User();
return user.save({
username: 'unverified-user',
password: 'mypass',
email: 'unverified-email@user.com',
});
})
.then(() => {
return verifyPassword('unverified-email@user.com', 'mypass', true);
})
.then(res => {
expect(res.status).toBe(400);
expect(res.text).toMatch('{"code":205,"error":"User email is not verified."}');
done();
})
.catch(err => {
fail(err);
done();
});
});
const user = new Parse.User();
await user.save({
username: 'unverified-user',
password: 'mypass',
email: 'unverified-email@example.com',
});
const res = await verifyPassword('unverified-email@example.com', 'mypass', true);
expect(res.status).toBe(400);
expect(res.data).toEqual({
code: Parse.Error.EMAIL_NOT_FOUND,
error: 'User email is not verified.',
});
});
it('verify password lock account if failed verify password attempts are above threshold', done => {
reconfigureServer({
appName: 'lockout threshold',
@@ -591,4 +585,83 @@ describe('Verify User Password', () => {
done();
});
});
it('verify password of user with unverified email with master key and ignoreEmailVerification=true', async () => {
await reconfigureServer({
publicServerURL: 'http://localhost:8378/',
appName: 'emailVerify',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
});
const user = new Parse.User();
user.setUsername('user');
user.setPassword('pass');
user.setEmail('test@example.com');
await user.signUp();
const { data: res } = await request({
method: 'POST',
url: Parse.serverURL + '/verifyPassword',
headers: {
'X-Parse-Master-Key': Parse.masterKey,
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
'Content-Type': 'application/json',
},
body: {
username: 'user',
password: 'pass',
ignoreEmailVerification: true,
},
json: true,
});
expect(res.objectId).toBe(user.id);
expect(Object.prototype.hasOwnProperty.call(res, 'sessionToken')).toEqual(false);
expect(Object.prototype.hasOwnProperty.call(res, 'password')).toEqual(false);
});
it('fails to verify password of user with unverified email with master key and ignoreEmailVerification=false', async () => {
await reconfigureServer({
publicServerURL: 'http://localhost:8378/',
appName: 'emailVerify',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
emailAdapter: MockEmailAdapterWithOptions({
fromAddress: 'parse@example.com',
apiKey: 'k',
domain: 'd',
}),
});
const user = new Parse.User();
user.setUsername('user');
user.setPassword('pass');
user.setEmail('test@example.com');
await user.signUp();
const res = await request({
method: 'POST',
url: Parse.serverURL + '/verifyPassword',
headers: {
'X-Parse-Master-Key': Parse.masterKey,
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
'Content-Type': 'application/json',
},
body: {
username: 'user',
password: 'pass',
ignoreEmailVerification: false,
},
json: true,
}).catch(e => e);
expect(res.status).toBe(400);
expect(res.text).toMatch(/User email is not verified/);
});
});
+2 -9
View File
@@ -1,6 +1,5 @@
const batch = require('../lib/batch');
const request = require('../lib/request');
const semver = require('semver');
const TestUtils = require('../lib/TestUtils');
const originalURL = '/parse/batch';
@@ -206,19 +205,13 @@ describe('batch', () => {
});
if (
(semver.satisfies(process.env.MONGODB_VERSION, '>=4.0.4') &&
process.env.MONGODB_TOPOLOGY === 'replicaset' &&
process.env.MONGODB_STORAGE_ENGINE === 'wiredTiger') ||
process.env.MONGODB_TOPOLOGY === 'replicaset' ||
process.env.PARSE_SERVER_TEST_DB === 'postgres'
) {
describe('transactions', () => {
beforeEach(async () => {
await TestUtils.destroyAllDataPermanently(true);
if (
semver.satisfies(process.env.MONGODB_VERSION, '>=4.0.4') &&
process.env.MONGODB_TOPOLOGY === 'replicaset' &&
process.env.MONGODB_STORAGE_ENGINE === 'wiredTiger'
) {
if (process.env.MONGODB_TOPOLOGY === 'replicaset') {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI:
+3
View File
@@ -0,0 +1,3 @@
Parse.Cloud.define('cloudCodeInFile', () => {
return 'It is possible to define cloud code in a file.';
});
+11
View File
@@ -0,0 +1,11 @@
{
"appName": "test",
"appId": "test",
"masterKey": "test",
"logLevel": "error",
"auth": {
"facebook": {
"appIds": "test"
}
}
}

Some files were not shown because too many files have changed in this diff Show More