Compare commits

..
815 Commits
Author SHA1 Message Date
semantic-release-bot 665216d6dc chore(release): 8.6.50 [skip ci]
## [8.6.50](https://github.com/parse-community/parse-server/compare/8.6.49...8.6.50) (2026-03-17)

### Bug Fixes

* Protected fields leak via LiveQuery afterEvent trigger ([GHSA-5hmj-jcgp-6hff](https://github.com/parse-community/parse-server/security/advisories/GHSA-5hmj-jcgp-6hff)) ([#10233](https://github.com/parse-community/parse-server/issues/10233)) ([743324e](https://github.com/parse-community/parse-server/commit/743324e71fa2a6693bea78c4589cf2211b210eb6))
2026-03-17 18:35:13 +00:00
Manuel 743324e71f fix: Protected fields leak via LiveQuery afterEvent trigger ([GHSA-5hmj-jcgp-6hff](https://github.com/parse-community/parse-server/security/advisories/GHSA-5hmj-jcgp-6hff)) (#10233) 2026-03-17 18:34:08 +00:00
semantic-release-bot b65262fd78 chore(release): 8.6.49 [skip ci]
## [8.6.49](https://github.com/parse-community/parse-server/compare/8.6.48...8.6.49) (2026-03-16)

### Bug Fixes

* Empty authData bypasses credential requirement on signup ([GHSA-wjqw-r9x4-j59v](https://github.com/parse-community/parse-server/security/advisories/GHSA-wjqw-r9x4-j59v)) ([#10220](https://github.com/parse-community/parse-server/issues/10220)) ([b62336b](https://github.com/parse-community/parse-server/commit/b62336be06d06e3e9fbf3365354363e381603f58))
2026-03-16 14:32:42 +00:00
Manuel b62336be06 fix: Empty authData bypasses credential requirement on signup ([GHSA-wjqw-r9x4-j59v](https://github.com/parse-community/parse-server/security/advisories/GHSA-wjqw-r9x4-j59v)) (#10220) 2026-03-16 14:31:07 +00:00
semantic-release-bot 122f4ace19 chore(release): 8.6.48 [skip ci]
## [8.6.48](https://github.com/parse-community/parse-server/compare/8.6.47...8.6.48) (2026-03-16)

### Bug Fixes

* Password reset token single-use bypass via concurrent requests ([GHSA-r3xq-68wh-gwvh](https://github.com/parse-community/parse-server/security/advisories/GHSA-r3xq-68wh-gwvh)) ([#10217](https://github.com/parse-community/parse-server/issues/10217)) ([83b4de0](https://github.com/parse-community/parse-server/commit/83b4de0b7ce722fac0ecbb5fe815e3da8fb6b8a0))
2026-03-16 03:00:32 +00:00
Manuel 83b4de0b7c fix: Password reset token single-use bypass via concurrent requests ([GHSA-r3xq-68wh-gwvh](https://github.com/parse-community/parse-server/security/advisories/GHSA-r3xq-68wh-gwvh)) (#10217) 2026-03-16 02:59:31 +00:00
semantic-release-bot 2af0d05736 chore(release): 8.6.47 [skip ci]
## [8.6.47](https://github.com/parse-community/parse-server/compare/8.6.46...8.6.47) (2026-03-15)

### Bug Fixes

* Cloud function dispatch crashes server via prototype chain traversal ([GHSA-4263-jgmp-7pf4](https://github.com/parse-community/parse-server/security/advisories/GHSA-4263-jgmp-7pf4)) ([#10211](https://github.com/parse-community/parse-server/issues/10211)) ([8d8c760](https://github.com/parse-community/parse-server/commit/8d8c7604790f931531ac31bd88c98eb3d995b9c5))
2026-03-15 17:14:16 +00:00
Manuel 8d8c760479 fix: Cloud function dispatch crashes server via prototype chain traversal ([GHSA-4263-jgmp-7pf4](https://github.com/parse-community/parse-server/security/advisories/GHSA-4263-jgmp-7pf4)) (#10211) 2026-03-15 17:13:17 +00:00
semantic-release-bot 5e17f25de6 chore(release): 8.6.46 [skip ci]
## [8.6.46](https://github.com/parse-community/parse-server/compare/8.6.45...8.6.46) (2026-03-15)

### Bug Fixes

* Revert accidental breaking default values for query complexity limits ([#10206](https://github.com/parse-community/parse-server/issues/10206)) ([a3a57c1](https://github.com/parse-community/parse-server/commit/a3a57c15077d0c9c902fd444de986915b942ab2f))
2026-03-15 03:35:32 +00:00
Manuel a3a57c1507 fix: Revert accidental breaking default values for query complexity limits (#10206) 2026-03-15 03:34:04 +00:00
semantic-release-bot 277ef7683b chore(release): 8.6.45 [skip ci]
## [8.6.45](https://github.com/parse-community/parse-server/compare/8.6.44...8.6.45) (2026-03-15)

### Bug Fixes

* Server crash via deeply nested query condition operators ([GHSA-9xp9-j92r-p88v](https://github.com/parse-community/parse-server/security/advisories/GHSA-9xp9-j92r-p88v)) ([#10203](https://github.com/parse-community/parse-server/issues/10203)) ([433fa8f](https://github.com/parse-community/parse-server/commit/433fa8fb19f813966871da8be874e1197a29b10b))
2026-03-15 02:55:44 +00:00
Manuel 433fa8fb19 fix: Server crash via deeply nested query condition operators ([GHSA-9xp9-j92r-p88v](https://github.com/parse-community/parse-server/security/advisories/GHSA-9xp9-j92r-p88v)) (#10203) 2026-03-15 02:54:44 +00:00
semantic-release-bot 65820cee6e chore(release): 8.6.44 [skip ci]
## [8.6.44](https://github.com/parse-community/parse-server/compare/8.6.43...8.6.44) (2026-03-14)

### Bug Fixes

* Schema poisoning via prototype pollution in deep copy ([GHSA-9ccr-fpp6-78qf](https://github.com/parse-community/parse-server/security/advisories/GHSA-9ccr-fpp6-78qf)) ([#10201](https://github.com/parse-community/parse-server/issues/10201)) ([6aec8ea](https://github.com/parse-community/parse-server/commit/6aec8ea9e17375930e55406d0c62a429505924cc))
2026-03-14 15:02:26 +00:00
Manuel 6aec8ea9e1 fix: Schema poisoning via prototype pollution in deep copy ([GHSA-9ccr-fpp6-78qf](https://github.com/parse-community/parse-server/security/advisories/GHSA-9ccr-fpp6-78qf)) (#10201) 2026-03-14 16:01:25 +01:00
semantic-release-bot 1a547771cc chore(release): 8.6.43 [skip ci]
## [8.6.43](https://github.com/parse-community/parse-server/compare/8.6.42...8.6.43) (2026-03-14)

### Bug Fixes

* LiveQuery subscription with invalid regular expression crashes server ([GHSA-827p-g5x5-h86c](https://github.com/parse-community/parse-server/security/advisories/GHSA-827p-g5x5-h86c)) ([#10199](https://github.com/parse-community/parse-server/issues/10199)) ([522f008](https://github.com/parse-community/parse-server/commit/522f008f64f6a4ae3c0b9a299ee6a53947a9c1ea))
2026-03-14 13:22:49 +00:00
Manuel 522f008f64 fix: LiveQuery subscription with invalid regular expression crashes server ([GHSA-827p-g5x5-h86c](https://github.com/parse-community/parse-server/security/advisories/GHSA-827p-g5x5-h86c)) (#10199) 2026-03-14 14:21:52 +01:00
semantic-release-bot 4ac6da4d8a chore(release): 8.6.42 [skip ci]
## [8.6.42](https://github.com/parse-community/parse-server/compare/8.6.41...8.6.42) (2026-03-13)

### Bug Fixes

* Session creation endpoint allows overwriting server-generated session fields ([GHSA-5v7g-9h8f-8pgg](https://github.com/parse-community/parse-server/security/advisories/GHSA-5v7g-9h8f-8pgg)) ([#10196](https://github.com/parse-community/parse-server/issues/10196)) ([2021b27](https://github.com/parse-community/parse-server/commit/2021b277e1ff1131cf79eb37bba07cc5fba872c7))
2026-03-13 23:44:01 +00:00
Manuel 2021b277e1 fix: Session creation endpoint allows overwriting server-generated session fields ([GHSA-5v7g-9h8f-8pgg](https://github.com/parse-community/parse-server/security/advisories/GHSA-5v7g-9h8f-8pgg)) (#10196) 2026-03-14 00:40:37 +01:00
semantic-release-bot 58e82c30c9 chore(release): 8.6.41 [skip ci]
## [8.6.41](https://github.com/parse-community/parse-server/compare/8.6.40...8.6.41) (2026-03-13)

### Bug Fixes

* Stored XSS filter bypass via Content-Type MIME parameter and missing XML extension blocklist entries ([GHSA-42ph-pf9q-cr72](https://github.com/parse-community/parse-server/security/advisories/GHSA-42ph-pf9q-cr72)) ([#10192](https://github.com/parse-community/parse-server/issues/10192)) ([c7599c5](https://github.com/parse-community/parse-server/commit/c7599c577a02b97eb5e76d4e20517b0283ae73c8))
2026-03-13 20:35:56 +00:00
Manuel c7599c577a fix: Stored XSS filter bypass via Content-Type MIME parameter and missing XML extension blocklist entries ([GHSA-42ph-pf9q-cr72](https://github.com/parse-community/parse-server/security/advisories/GHSA-42ph-pf9q-cr72)) (#10192) 2026-03-13 21:34:50 +01:00
semantic-release-bot e90db39853 chore(release): 8.6.40 [skip ci]
## [8.6.40](https://github.com/parse-community/parse-server/compare/8.6.39...8.6.40) (2026-03-12)

### Bug Fixes

* GraphQL WebSocket endpoint bypasses security middleware ([GHSA-p2x3-8689-cwpg](https://github.com/parse-community/parse-server/security/advisories/GHSA-p2x3-8689-cwpg)) ([#10190](https://github.com/parse-community/parse-server/issues/10190)) ([21330d1](https://github.com/parse-community/parse-server/commit/21330d146c68b57a930a58b8a8cd9fbf09436cf3))
2026-03-12 14:25:14 +00:00
Manuel 21330d146c fix: GraphQL WebSocket endpoint bypasses security middleware ([GHSA-p2x3-8689-cwpg](https://github.com/parse-community/parse-server/security/advisories/GHSA-p2x3-8689-cwpg)) (#10190) 2026-03-12 14:24:06 +00:00
semantic-release-bot bb2427de56 chore(release): 8.6.39 [skip ci]
## [8.6.39](https://github.com/parse-community/parse-server/compare/8.6.38...8.6.39) (2026-03-11)

### Bug Fixes

* OAuth2 adapter app ID validation sends wrong token to introspection endpoint ([GHSA-69xg-f649-w5g2](https://github.com/parse-community/parse-server/security/advisories/GHSA-69xg-f649-w5g2)) ([#10188](https://github.com/parse-community/parse-server/issues/10188)) ([fd6f6a6](https://github.com/parse-community/parse-server/commit/fd6f6a6ea9df631a63702d24496046ecccc610d6))
2026-03-11 23:48:45 +00:00
Manuel fd6f6a6ea9 fix: OAuth2 adapter app ID validation sends wrong token to introspection endpoint ([GHSA-69xg-f649-w5g2](https://github.com/parse-community/parse-server/security/advisories/GHSA-69xg-f649-w5g2)) (#10188) 2026-03-11 23:47:44 +00:00
semantic-release-bot ae8d8e3b09 chore(release): 8.6.38 [skip ci]
## [8.6.38](https://github.com/parse-community/parse-server/compare/8.6.37...8.6.38) (2026-03-11)

### Bug Fixes

* Account takeover via operator injection in authentication data identifier ([GHSA-5fw2-8jcv-xh87](https://github.com/parse-community/parse-server/security/advisories/GHSA-5fw2-8jcv-xh87)) ([#10186](https://github.com/parse-community/parse-server/issues/10186)) ([93425df](https://github.com/parse-community/parse-server/commit/93425df2bc9368eab89644c93fa9ef481c043e3a))
2026-03-11 18:08:26 +00:00
Manuel 93425df2bc fix: Account takeover via operator injection in authentication data identifier ([GHSA-5fw2-8jcv-xh87](https://github.com/parse-community/parse-server/security/advisories/GHSA-5fw2-8jcv-xh87)) (#10186) 2026-03-11 18:07:21 +00:00
semantic-release-bot 5990ad9245 chore(release): 8.6.37 [skip ci]
## [8.6.37](https://github.com/parse-community/parse-server/compare/8.6.36...8.6.37) (2026-03-11)

### Bug Fixes

* OAuth2 adapter shares mutable state across providers via singleton instance ([GHSA-2cjm-2gwv-m892](https://github.com/parse-community/parse-server/security/advisories/GHSA-2cjm-2gwv-m892)) ([#10184](https://github.com/parse-community/parse-server/issues/10184)) ([6afa431](https://github.com/parse-community/parse-server/commit/6afa4315ea691d8fe36ed39f00fb50fd8affb691))
2026-03-11 16:38:25 +00:00
Manuel 6afa4315ea fix: OAuth2 adapter shares mutable state across providers via singleton instance ([GHSA-2cjm-2gwv-m892](https://github.com/parse-community/parse-server/security/advisories/GHSA-2cjm-2gwv-m892)) (#10184) 2026-03-11 16:36:53 +00:00
semantic-release-bot ee3a432182 chore(release): 8.6.36 [skip ci]
## [8.6.36](https://github.com/parse-community/parse-server/compare/8.6.35...8.6.36) (2026-03-11)

### Bug Fixes

* SQL injection via query field name when using PostgreSQL ([GHSA-c442-97qw-j6c6](https://github.com/parse-community/parse-server/security/advisories/GHSA-c442-97qw-j6c6)) ([#10182](https://github.com/parse-community/parse-server/issues/10182)) ([0b0398b](https://github.com/parse-community/parse-server/commit/0b0398bd23cb243c59c13c94866454668064c013))
2026-03-11 14:42:06 +00:00
Manuel 0b0398bd23 fix: SQL injection via query field name when using PostgreSQL ([GHSA-c442-97qw-j6c6](https://github.com/parse-community/parse-server/security/advisories/GHSA-c442-97qw-j6c6)) (#10182) 2026-03-11 14:41:10 +00:00
Manuel add233b861 SQL injection via query field name when using PostgreSQL ([GHSA-c442-97qw-j6c6](https://github.com/parse-community/parse-server/security/advisories/GHSA-c442-97qw-j6c6)) (#10179) 2026-03-11 14:22:31 +00:00
semantic-release-bot e48c3b5173 chore(release): 8.6.35 [skip ci]
## [8.6.35](https://github.com/parse-community/parse-server/compare/8.6.34...8.6.35) (2026-03-10)

### Bug Fixes

* Protected fields bypass via LiveQuery subscription WHERE clause ([GHSA-j7mm-f4rv-6q6q](https://github.com/parse-community/parse-server/security/advisories/GHSA-j7mm-f4rv-6q6q)) ([#10176](https://github.com/parse-community/parse-server/issues/10176)) ([dfc7e69](https://github.com/parse-community/parse-server/commit/dfc7e69b95c719589d267f50935d8660e2201a8c))
2026-03-10 20:54:13 +00:00
Manuel dfc7e69b95 fix: Protected fields bypass via LiveQuery subscription WHERE clause ([GHSA-j7mm-f4rv-6q6q](https://github.com/parse-community/parse-server/security/advisories/GHSA-j7mm-f4rv-6q6q)) (#10176) 2026-03-10 20:53:16 +00:00
semantic-release-bot 654f2266d8 chore(release): 8.6.34 [skip ci]
## [8.6.34](https://github.com/parse-community/parse-server/compare/8.6.33...8.6.34) (2026-03-10)

### Bug Fixes

* User enumeration via email verification endpoint ([GHSA-w54v-hf9p-8856](https://github.com/parse-community/parse-server/security/advisories/GHSA-w54v-hf9p-8856)) ([#10173](https://github.com/parse-community/parse-server/issues/10173)) ([d3defb8](https://github.com/parse-community/parse-server/commit/d3defb887d802aaef12600a1f0c9b729ea06eff9))
2026-03-10 14:00:34 +00:00
Manuel d3defb887d fix: User enumeration via email verification endpoint ([GHSA-w54v-hf9p-8856](https://github.com/parse-community/parse-server/security/advisories/GHSA-w54v-hf9p-8856)) (#10173) 2026-03-10 13:59:30 +00:00
semantic-release-bot c1dc6d3c1a chore(release): 8.6.33 [skip ci]
## [8.6.33](https://github.com/parse-community/parse-server/compare/8.6.32...8.6.33) (2026-03-10)

### Bug Fixes

* MFA recovery codes not consumed after use ([GHSA-4hf6-3x24-c9m8](https://github.com/parse-community/parse-server/security/advisories/GHSA-4hf6-3x24-c9m8)) ([#10171](https://github.com/parse-community/parse-server/issues/10171)) ([a00c4fa](https://github.com/parse-community/parse-server/commit/a00c4fa24ff059081d2617dd435f8ee3de215000))
2026-03-10 04:23:27 +00:00
Manuel a00c4fa24f fix: MFA recovery codes not consumed after use ([GHSA-4hf6-3x24-c9m8](https://github.com/parse-community/parse-server/security/advisories/GHSA-4hf6-3x24-c9m8)) (#10171) 2026-03-10 04:22:30 +00:00
semantic-release-bot e092f2cdad chore(release): 8.6.32 [skip ci]
## [8.6.32](https://github.com/parse-community/parse-server/compare/8.6.31...8.6.32) (2026-03-10)

### Bug Fixes

* Protected fields bypass via dot-notation in query and sort ([GHSA-r2m8-pxm9-9c4g](https://github.com/parse-community/parse-server/security/advisories/GHSA-r2m8-pxm9-9c4g)) ([#10168](https://github.com/parse-community/parse-server/issues/10168)) ([1787db3](https://github.com/parse-community/parse-server/commit/1787db3244acca5ced180eb9814e1cfad364d826))
2026-03-10 02:05:32 +00:00
Manuel 1787db3244 fix: Protected fields bypass via dot-notation in query and sort ([GHSA-r2m8-pxm9-9c4g](https://github.com/parse-community/parse-server/security/advisories/GHSA-r2m8-pxm9-9c4g)) (#10168) 2026-03-10 02:04:35 +00:00
semantic-release-bot 44d6ff4d4f chore(release): 8.6.31 [skip ci]
## [8.6.31](https://github.com/parse-community/parse-server/compare/8.6.30...8.6.31) (2026-03-10)

### Bug Fixes

* SQL Injection via dot-notation sub-key name in `Increment` operation on PostgreSQL ([GHSA-gqpp-xgvh-9h7h](https://github.com/parse-community/parse-server/security/advisories/GHSA-gqpp-xgvh-9h7h)) ([#10166](https://github.com/parse-community/parse-server/issues/10166)) ([aa0de68](https://github.com/parse-community/parse-server/commit/aa0de68d20a23338c70db54f6c54f6028d263de1))
2026-03-10 01:04:37 +00:00
Manuel aa0de68d20 fix: SQL Injection via dot-notation sub-key name in Increment operation on PostgreSQL ([GHSA-gqpp-xgvh-9h7h](https://github.com/parse-community/parse-server/security/advisories/GHSA-gqpp-xgvh-9h7h)) (#10166) 2026-03-10 01:03:15 +00:00
semantic-release-bot 16a583da10 chore(release): 8.6.30 [skip ci]
## [8.6.30](https://github.com/parse-community/parse-server/compare/8.6.29...8.6.30) (2026-03-09)

### Bug Fixes

* Stored XSS via file upload of HTML-renderable file types ([GHSA-v5hf-f4c3-m5rv](https://github.com/parse-community/parse-server/security/advisories/GHSA-v5hf-f4c3-m5rv)) ([#10164](https://github.com/parse-community/parse-server/issues/10164)) ([90936f9](https://github.com/parse-community/parse-server/commit/90936f9ca2d6d4a886b5549a8cdfabda98fcc168))
2026-03-09 23:51:16 +00:00
Manuel 90936f9ca2 fix: Stored XSS via file upload of HTML-renderable file types ([GHSA-v5hf-f4c3-m5rv](https://github.com/parse-community/parse-server/security/advisories/GHSA-v5hf-f4c3-m5rv)) (#10164) 2026-03-09 23:50:14 +00:00
semantic-release-bot 38360c53ba chore(release): 8.6.29 [skip ci]
## [8.6.29](https://github.com/parse-community/parse-server/compare/8.6.28...8.6.29) (2026-03-09)

### Bug Fixes

* SQL injection via `Increment` operation on nested object field in PostgreSQL ([GHSA-q3vj-96h2-gwvg](https://github.com/parse-community/parse-server/security/advisories/GHSA-q3vj-96h2-gwvg)) ([#10163](https://github.com/parse-community/parse-server/issues/10163)) ([c92022f](https://github.com/parse-community/parse-server/commit/c92022f1ff12b119d7a6a807426925ce7d52e5ab))
2026-03-09 21:31:36 +00:00
Manuel c92022f1ff fix: SQL injection via Increment operation on nested object field in PostgreSQL ([GHSA-q3vj-96h2-gwvg](https://github.com/parse-community/parse-server/security/advisories/GHSA-q3vj-96h2-gwvg)) (#10163) 2026-03-09 21:30:40 +00:00
semantic-release-bot 0564c8438a chore(release): 8.6.28 [skip ci]
## [8.6.28](https://github.com/parse-community/parse-server/compare/8.6.27...8.6.28) (2026-03-09)

### Bug Fixes

* SQL injection via dot-notation field name in PostgreSQL ([GHSA-qpr4-jrj4-6f27](https://github.com/parse-community/parse-server/security/advisories/GHSA-qpr4-jrj4-6f27)) ([#10160](https://github.com/parse-community/parse-server/issues/10160)) ([83f38fa](https://github.com/parse-community/parse-server/commit/83f38faab25d89e7bbe7c5c2087c5ee616479975))
2026-03-09 20:29:40 +00:00
Manuel 83f38faab2 fix: SQL injection via dot-notation field name in PostgreSQL ([GHSA-qpr4-jrj4-6f27](https://github.com/parse-community/parse-server/security/advisories/GHSA-qpr4-jrj4-6f27)) (#10160) 2026-03-09 20:28:21 +00:00
semantic-release-bot 7edb8fcb67 chore(release): 8.6.27 [skip ci]
## [8.6.27](https://github.com/parse-community/parse-server/compare/8.6.26...8.6.27) (2026-03-09)

### Bug Fixes

*  LiveQuery `regexTimeout` default value not applied ([#10157](https://github.com/parse-community/parse-server/issues/10157)) ([94c4f52](https://github.com/parse-community/parse-server/commit/94c4f523e02be6d82f006cbacb18bec5a1de7f2e))
2026-03-09 18:09:36 +00:00
Manuel 94c4f523e0 fix: LiveQuery regexTimeout default value not applied (#10157) 2026-03-09 18:07:12 +00:00
semantic-release-bot 01fad124d4 chore(release): 8.6.26 [skip ci]
## [8.6.26](https://github.com/parse-community/parse-server/compare/8.6.25...8.6.26) (2026-03-09)

### Bug Fixes

* LDAP injection via unsanitized user input in DN and group filter construction ([GHSA-7m6r-fhh7-r47c](https://github.com/parse-community/parse-server/security/advisories/GHSA-7m6r-fhh7-r47c)) ([#10153](https://github.com/parse-community/parse-server/issues/10153)) ([2370611](https://github.com/parse-community/parse-server/commit/23706117220a7489558683f72e8fdc0983cf8dfc))
2026-03-09 14:05:09 +00:00
Manuel 2370611722 fix: LDAP injection via unsanitized user input in DN and group filter construction ([GHSA-7m6r-fhh7-r47c](https://github.com/parse-community/parse-server/security/advisories/GHSA-7m6r-fhh7-r47c)) (#10153) 2026-03-09 14:04:08 +00:00
semantic-release-bot 9e7a19f7ad chore(release): 8.6.25 [skip ci]
## [8.6.25](https://github.com/parse-community/parse-server/compare/8.6.24...8.6.25) (2026-03-09)

### Bug Fixes

* Classes `_GraphQLConfig` and `_Audience` master key bypass via generic class routes ([GHSA-7xg7-rqf6-pw6c](https://github.com/parse-community/parse-server/security/advisories/GHSA-7xg7-rqf6-pw6c)) ([#10152](https://github.com/parse-community/parse-server/issues/10152)) ([94aa653](https://github.com/parse-community/parse-server/commit/94aa65318c6a4b8d7b8f0b98c96d52e36d33dc9a))
2026-03-09 03:42:25 +00:00
Manuel 94aa65318c fix: Classes _GraphQLConfig and _Audience master key bypass via generic class routes ([GHSA-7xg7-rqf6-pw6c](https://github.com/parse-community/parse-server/security/advisories/GHSA-7xg7-rqf6-pw6c)) (#10152) 2026-03-09 03:41:25 +00:00
semantic-release-bot efd0ac639b chore(release): 8.6.24 [skip ci]
## [8.6.24](https://github.com/parse-community/parse-server/compare/8.6.23...8.6.24) (2026-03-09)

### Bug Fixes

* Concurrent signup with same authentication creates duplicate users ([#10150](https://github.com/parse-community/parse-server/issues/10150)) ([fac8f33](https://github.com/parse-community/parse-server/commit/fac8f338ecdfeffcaed21d7e0729e2cf1ea9947d))
2026-03-09 02:06:54 +00:00
Manuel fac8f338ec fix: Concurrent signup with same authentication creates duplicate users (#10150) 2026-03-09 02:05:49 +00:00
semantic-release-bot f2058fb5e3 chore(release): 8.6.23 [skip ci]
## [8.6.23](https://github.com/parse-community/parse-server/compare/8.6.22...8.6.23) (2026-03-08)

### Bug Fixes

* Rate limit bypass via batch request endpoint ([GHSA-775h-3xrc-c228](https://github.com/parse-community/parse-server/security/advisories/GHSA-775h-3xrc-c228)) ([#10148](https://github.com/parse-community/parse-server/issues/10148)) ([48b94ae](https://github.com/parse-community/parse-server/commit/48b94aed12006b5f1e501c0de8284a9541e60b1b))
2026-03-08 20:31:41 +00:00
Manuel 48b94aed12 fix: Rate limit bypass via batch request endpoint ([GHSA-775h-3xrc-c228](https://github.com/parse-community/parse-server/security/advisories/GHSA-775h-3xrc-c228)) (#10148) 2026-03-08 20:30:42 +00:00
semantic-release-bot fa24c2c5f8 chore(release): 8.6.22 [skip ci]
## [8.6.22](https://github.com/parse-community/parse-server/compare/8.6.21...8.6.22) (2026-03-08)

### Bug Fixes

* Parse Server OAuth2 authentication adapter account takeover via identity spoofing ([GHSA-fr88-w35c-r596](https://github.com/parse-community/parse-server/security/advisories/GHSA-fr88-w35c-r596)) ([#10146](https://github.com/parse-community/parse-server/issues/10146)) ([238110b](https://github.com/parse-community/parse-server/commit/238110b5f63f47d9ef128bbd5d37795a85f31891))
2026-03-08 18:29:09 +00:00
Manuel 238110b5f6 fix: Parse Server OAuth2 authentication adapter account takeover via identity spoofing ([GHSA-fr88-w35c-r596](https://github.com/parse-community/parse-server/security/advisories/GHSA-fr88-w35c-r596)) (#10146) 2026-03-08 18:27:49 +00:00
semantic-release-bot cb07a353b1 chore(release): 8.6.21 [skip ci]
## [8.6.21](https://github.com/parse-community/parse-server/compare/8.6.20...8.6.21) (2026-03-08)

### Bug Fixes

* Parse Server session token exfiltration via `redirectClassNameForKey` query parameter ([GHSA-6r2j-cxgf-495f](https://github.com/parse-community/parse-server/security/advisories/GHSA-6r2j-cxgf-495f)) ([#10144](https://github.com/parse-community/parse-server/issues/10144)) ([721abe8](https://github.com/parse-community/parse-server/commit/721abe8b7c76a3143936936a720d3782547d4d9c))
2026-03-08 17:24:45 +00:00
Manuel 721abe8b7c fix: Parse Server session token exfiltration via redirectClassNameForKey query parameter ([GHSA-6r2j-cxgf-495f](https://github.com/parse-community/parse-server/security/advisories/GHSA-6r2j-cxgf-495f)) (#10144) 2026-03-08 17:23:47 +00:00
semantic-release-bot bf248d80db chore(release): 8.6.20 [skip ci]
## [8.6.20](https://github.com/parse-community/parse-server/compare/8.6.19...8.6.20) (2026-03-08)

### Bug Fixes

* Parse Server role escalation and CLP bypass via direct `_Join table write ([GHSA-5f92-jrq3-28rc](https://github.com/parse-community/parse-server/security/advisories/GHSA-5f92-jrq3-28rc)) ([#10142](https://github.com/parse-community/parse-server/issues/10142)) ([1c58ef7](https://github.com/parse-community/parse-server/commit/1c58ef787894dcb67623c0fb889820ee1d2ddf1b))
2026-03-08 16:27:50 +00:00
Manuel 1c58ef7878 fix: Parse Server role escalation and CLP bypass via direct `_Join table write ([GHSA-5f92-jrq3-28rc](https://github.com/parse-community/parse-server/security/advisories/GHSA-5f92-jrq3-28rc)) (#10142) 2026-03-08 16:26:52 +00:00
semantic-release-bot efb6cfefc3 chore(release): 8.6.19 [skip ci]
## [8.6.19](https://github.com/parse-community/parse-server/compare/8.6.18...8.6.19) (2026-03-08)

### Bug Fixes

* Protected fields bypass via logical query operators ([GHSA-72hp-qff8-4pvv](https://github.com/parse-community/parse-server/security/advisories/GHSA-72hp-qff8-4pvv)) ([#10139](https://github.com/parse-community/parse-server/issues/10139)) ([2c11c61](https://github.com/parse-community/parse-server/commit/2c11c616cb911ceed322c8d4dd204de9a0abc323))
2026-03-08 15:26:51 +00:00
Manuel 2c11c616cb fix: Protected fields bypass via logical query operators ([GHSA-72hp-qff8-4pvv](https://github.com/parse-community/parse-server/security/advisories/GHSA-72hp-qff8-4pvv)) (#10139) 2026-03-08 15:25:37 +00:00
semantic-release-bot 0d4e3bbb9b chore(release): 8.6.18 [skip ci]
## [8.6.18](https://github.com/parse-community/parse-server/compare/8.6.17...8.6.18) (2026-03-08)

### Bug Fixes

* Missing audience validation in Keycloak authentication adapter ([GHSA-48mh-j4p5-7j9v](https://github.com/parse-community/parse-server/security/advisories/GHSA-48mh-j4p5-7j9v)) ([#10138](https://github.com/parse-community/parse-server/issues/10138)) ([572be64](https://github.com/parse-community/parse-server/commit/572be64d17935870a94840fe541ae91cc09143c2))
2026-03-08 03:51:33 +00:00
Manuel 572be64d17 fix: Missing audience validation in Keycloak authentication adapter ([GHSA-48mh-j4p5-7j9v](https://github.com/parse-community/parse-server/security/advisories/GHSA-48mh-j4p5-7j9v)) (#10138) 2026-03-08 03:50:20 +00:00
semantic-release-bot e212141829 chore(release): 8.6.17 [skip ci]
## [8.6.17](https://github.com/parse-community/parse-server/compare/8.6.16...8.6.17) (2026-03-08)

### Bug Fixes

* Stored cross-site scripting (XSS) via SVG file upload ([GHSA-hcj7-6gxh-24ww](https://github.com/parse-community/parse-server/security/advisories/GHSA-hcj7-6gxh-24ww)) ([#10135](https://github.com/parse-community/parse-server/issues/10135)) ([fed2d39](https://github.com/parse-community/parse-server/commit/fed2d39f1dc4a64d093e77d54ebc7f6963918d15))
2026-03-08 02:06:16 +00:00
Manuel fed2d39f1d fix: Stored cross-site scripting (XSS) via SVG file upload ([GHSA-hcj7-6gxh-24ww](https://github.com/parse-community/parse-server/security/advisories/GHSA-hcj7-6gxh-24ww)) (#10135) 2026-03-08 02:05:07 +00:00
semantic-release-bot 20abb1cf36 chore(release): 8.6.16 [skip ci]
## [8.6.16](https://github.com/parse-community/parse-server/compare/8.6.15...8.6.16) (2026-03-08)

### Bug Fixes

* Bypass of class-level permissions in LiveQuery ([GHSA-7ch5-98q2-7289](https://github.com/parse-community/parse-server/security/advisories/GHSA-7ch5-98q2-7289)) ([#10134](https://github.com/parse-community/parse-server/issues/10134)) ([6fecec5](https://github.com/parse-community/parse-server/commit/6fecec52c53f24baefbfd5b5899bf295069447d6))
2026-03-08 01:16:11 +00:00
Manuel 6fecec52c5 fix: Bypass of class-level permissions in LiveQuery ([GHSA-7ch5-98q2-7289](https://github.com/parse-community/parse-server/security/advisories/GHSA-7ch5-98q2-7289)) (#10134) 2026-03-08 01:15:17 +00:00
semantic-release-bot 0aeedb29a2 chore(release): 8.6.15 [skip ci]
## [8.6.15](https://github.com/parse-community/parse-server/compare/8.6.14...8.6.15) (2026-03-07)

### Bug Fixes

* Denial-of-service via unbounded query complexity in REST and GraphQL API ([GHSA-cmj3-wx7h-ffvg](https://github.com/parse-community/parse-server/security/advisories/GHSA-cmj3-wx7h-ffvg)) ([#10131](https://github.com/parse-community/parse-server/issues/10131)) ([23ac059](https://github.com/parse-community/parse-server/commit/23ac05938b64451322b60fe6b031b4893ff62b67))
2026-03-07 23:34:26 +00:00
Manuel 23ac05938b fix: Denial-of-service via unbounded query complexity in REST and GraphQL API ([GHSA-cmj3-wx7h-ffvg](https://github.com/parse-community/parse-server/security/advisories/GHSA-cmj3-wx7h-ffvg)) (#10131) 2026-03-07 23:33:27 +00:00
semantic-release-bot c97554fc4a chore(release): 8.6.14 [skip ci]
## [8.6.14](https://github.com/parse-community/parse-server/compare/8.6.13...8.6.14) (2026-03-07)

### Bug Fixes

* NoSQL injection via token type in password reset and email verification endpoints ([GHSA-vgjh-hmwf-c588](https://github.com/parse-community/parse-server/security/advisories/GHSA-vgjh-hmwf-c588)) ([#10129](https://github.com/parse-community/parse-server/issues/10129)) ([88eed83](https://github.com/parse-community/parse-server/commit/88eed83ff818027a960274e1de30a487812a6db4))
2026-03-07 19:17:27 +00:00
Manuel 88eed83ff8 fix: NoSQL injection via token type in password reset and email verification endpoints ([GHSA-vgjh-hmwf-c588](https://github.com/parse-community/parse-server/security/advisories/GHSA-vgjh-hmwf-c588)) (#10129) 2026-03-07 19:16:26 +00:00
semantic-release-bot f376abb60e chore(release): 8.6.13 [skip ci]
## [8.6.13](https://github.com/parse-community/parse-server/compare/8.6.12...8.6.13) (2026-03-07)

### Bug Fixes

* Denial of Service (DoS) and Cloud Function Dispatch Bypass via Prototype Chain Resolution ([GHSA-5j86-7r7m-p8h6](https://github.com/parse-community/parse-server/security/advisories/GHSA-5j86-7r7m-p8h6)) ([#10124](https://github.com/parse-community/parse-server/issues/10124)) ([5c2d60a](https://github.com/parse-community/parse-server/commit/5c2d60a2f3733ca3a4cb782d552ba38c526aee0b))
2026-03-07 17:39:30 +00:00
Manuel 5c2d60a2f3 fix: Denial of Service (DoS) and Cloud Function Dispatch Bypass via Prototype Chain Resolution ([GHSA-5j86-7r7m-p8h6](https://github.com/parse-community/parse-server/security/advisories/GHSA-5j86-7r7m-p8h6)) (#10124) 2026-03-07 17:38:28 +00:00
semantic-release-bot 8c8eb46022 chore(release): 8.6.12 [skip ci]
## [8.6.12](https://github.com/parse-community/parse-server/compare/8.6.11...8.6.12) (2026-03-07)

### Bug Fixes

* Denylist `requestKeywordDenylist` keyword scan bypass through nested object placement ([GHSA-q342-9w2p-57fp](https://github.com/parse-community/parse-server/security/advisories/GHSA-q342-9w2p-57fp)) ([#10122](https://github.com/parse-community/parse-server/issues/10122)) ([2b52feb](https://github.com/parse-community/parse-server/commit/2b52feb06448e5c683017fa2e3d2038a5d8d6085))
2026-03-07 16:42:04 +00:00
Manuel 2b52feb064 fix: Denylist requestKeywordDenylist keyword scan bypass through nested object placement ([GHSA-q342-9w2p-57fp](https://github.com/parse-community/parse-server/security/advisories/GHSA-q342-9w2p-57fp)) (#10122) 2026-03-07 16:40:49 +00:00
semantic-release-bot aa7c57e917 chore(release): 8.6.11 [skip ci]
## [8.6.11](https://github.com/parse-community/parse-server/compare/8.6.10...8.6.11) (2026-03-07)

### Bug Fixes

* Regular Expression Denial of Service (ReDoS) via `$regex` query in LiveQuery ([GHSA-mf3j-86qx-cq5j](https://github.com/parse-community/parse-server/security/advisories/GHSA-mf3j-86qx-cq5j)) ([#10120](https://github.com/parse-community/parse-server/issues/10120)) ([42bd2f0](https://github.com/parse-community/parse-server/commit/42bd2f07bd3b425cac1e3c48161688cc4d54ef41))
2026-03-07 02:15:33 +00:00
Manuel 42bd2f07bd fix: Regular Expression Denial of Service (ReDoS) via $regex query in LiveQuery ([GHSA-mf3j-86qx-cq5j](https://github.com/parse-community/parse-server/security/advisories/GHSA-mf3j-86qx-cq5j)) (#10120) 2026-03-07 02:14:34 +00:00
semantic-release-bot 72af528d53 chore(release): 8.6.10 [skip ci]
## [8.6.10](https://github.com/parse-community/parse-server/compare/8.6.9...8.6.10) (2026-03-06)

### Bug Fixes

* JWT audience validation bypass in Google, Apple, and Facebook authentication adapters ([GHSA-x6fw-778m-wr9v](https://github.com/parse-community/parse-server/security/advisories/GHSA-x6fw-778m-wr9v)) ([#10114](https://github.com/parse-community/parse-server/issues/10114)) ([1da3123](https://github.com/parse-community/parse-server/commit/1da312311827a7790ad97852e8672119d40d529a))
2026-03-06 05:13:03 +00:00
Manuel 1da3123118 fix: JWT audience validation bypass in Google, Apple, and Facebook authentication adapters ([GHSA-x6fw-778m-wr9v](https://github.com/parse-community/parse-server/security/advisories/GHSA-x6fw-778m-wr9v)) (#10114) 2026-03-06 05:12:09 +00:00
semantic-release-bot 79bd170d53 chore(release): 8.6.9 [skip ci]
## [8.6.9](https://github.com/parse-community/parse-server/compare/8.6.8...8.6.9) (2026-03-06)

### Bug Fixes

* File metadata endpoint bypasses `beforeFind` / `afterFind` trigger authorization ([GHSA-hwx8-q9cg-mqmc](https://github.com/parse-community/parse-server/security/advisories/GHSA-hwx8-q9cg-mqmc)) ([#10107](https://github.com/parse-community/parse-server/issues/10107)) ([a7358b1](https://github.com/parse-community/parse-server/commit/a7358b1e0c58ef4c6b5e0ade772bf673b5f78fd0))
2026-03-06 01:06:26 +00:00
Manuel a7358b1e0c fix: File metadata endpoint bypasses beforeFind / afterFind trigger authorization ([GHSA-hwx8-q9cg-mqmc](https://github.com/parse-community/parse-server/security/advisories/GHSA-hwx8-q9cg-mqmc)) (#10107) 2026-03-06 01:05:25 +00:00
semantic-release-bot cf030af7f5 chore(release): 8.6.8 [skip ci]
## [8.6.8](https://github.com/parse-community/parse-server/compare/8.6.7...8.6.8) (2026-03-05)

### Bug Fixes

* `PagesRouter` path traversal allows reading files outside configured pages directory ([GHSA-hm3f-q6rw-m6wh](https://github.com/parse-community/parse-server/security/advisories/GHSA-hm3f-q6rw-m6wh)) ([#10105](https://github.com/parse-community/parse-server/issues/10105)) ([d5a057d](https://github.com/parse-community/parse-server/commit/d5a057d1a7cd5f6713d93afa3ad6f764f74b6ed2))
2026-03-05 23:50:37 +00:00
Manuel d5a057d1a7 fix: PagesRouter path traversal allows reading files outside configured pages directory ([GHSA-hm3f-q6rw-m6wh](https://github.com/parse-community/parse-server/security/advisories/GHSA-hm3f-q6rw-m6wh)) (#10105) 2026-03-05 23:49:20 +00:00
semantic-release-bot 2c43ddb74e chore(release): 8.6.7 [skip ci]
## [8.6.7](https://github.com/parse-community/parse-server/compare/8.6.6...8.6.7) (2026-03-05)

### Bug Fixes

* Malformed `$regex` query leaks database error details in API response (GHSA-9cp7-3q5w-j92g) ([#10102](https://github.com/parse-community/parse-server/issues/10102)) ([07870f5](https://github.com/parse-community/parse-server/commit/07870f59eec03f5c2a5fb1732cb28787ca3f8152))
2026-03-05 20:46:40 +00:00
Manuel 07870f59ee fix: Malformed $regex query leaks database error details in API response (GHSA-9cp7-3q5w-j92g) (#10102) 2026-03-05 20:45:39 +00:00
semantic-release-bot 0994d6e9b8 chore(release): 8.6.6 [skip ci]
## [8.6.6](https://github.com/parse-community/parse-server/compare/8.6.5...8.6.6) (2026-03-05)

### Bug Fixes

* Endpoint `/loginAs` allows `readOnlyMasterKey` to gain full read and write access as any user ([GHSA-79wj-8rqv-jvp5](https://github.com/parse-community/parse-server/security/advisories/GHSA-79wj-8rqv-jvp5)) ([#10099](https://github.com/parse-community/parse-server/issues/10099)) ([0c940b7](https://github.com/parse-community/parse-server/commit/0c940b70891c947fbf6c55536ed95ae300c23350))
2026-03-05 02:29:11 +00:00
Manuel 0c940b7089 fix: Endpoint /loginAs allows readOnlyMasterKey to gain full read and write access as any user ([GHSA-79wj-8rqv-jvp5](https://github.com/parse-community/parse-server/security/advisories/GHSA-79wj-8rqv-jvp5)) (#10099) 2026-03-05 02:28:05 +00:00
semantic-release-bot bfe11c4917 chore(release): 8.6.5 [skip ci]
## [8.6.5](https://github.com/parse-community/parse-server/compare/8.6.4...8.6.5) (2026-03-05)

### Bug Fixes

* File creation and deletion bypasses `readOnlyMasterKey` write restriction (GHSA-xfh7-phr7-gr2x) ([#10096](https://github.com/parse-community/parse-server/issues/10096)) ([07bddc0](https://github.com/parse-community/parse-server/commit/07bddc0850c0eebb51219fe1d5d342f4412461ba))
2026-03-05 01:45:59 +00:00
Manuel 07bddc0850 fix: File creation and deletion bypasses readOnlyMasterKey write restriction (GHSA-xfh7-phr7-gr2x) (#10096) 2026-03-05 01:44:56 +00:00
semantic-release-bot d39387f44d chore(release): 8.6.4 [skip ci]
## [8.6.4](https://github.com/parse-community/parse-server/compare/8.6.3...8.6.4) (2026-03-04)

### Bug Fixes

* Cloud Hooks and Cloud Jobs bypass `readOnlyMasterKey` write restriction (GHSA-vc89-5g3r-cmhh) ([#10089](https://github.com/parse-community/parse-server/issues/10089)) ([6c79da9](https://github.com/parse-community/parse-server/commit/6c79da91fc5ec6f2a0bb69a0ca6a886c1585754f))
2026-03-04 00:16:10 +00:00
Manuel 6c79da91fc fix: Cloud Hooks and Cloud Jobs bypass readOnlyMasterKey write restriction (GHSA-vc89-5g3r-cmhh) (#10089) 2026-03-04 00:15:09 +00:00
semantic-release-bot 9f28ff5663 chore(release): 8.6.3 [skip ci]
## [8.6.3](https://github.com/parse-community/parse-server/compare/8.6.2...8.6.3) (2026-02-23)

### Bug Fixes

* JWT Algorithm Confusion in Google Auth Adapter ([GHSA-4q3h-vp4r-prv2](https://github.com/parse-community/parse-server/security/advisories/GHSA-4q3h-vp4r-prv2)) ([#10073](https://github.com/parse-community/parse-server/issues/10073)) ([9b94083](https://github.com/parse-community/parse-server/commit/9b94083accb7f3e72c6b8126c195c7a03dd2dfd7))
2026-02-23 22:06:23 +00:00
Manuel 9b94083acc fix: JWT Algorithm Confusion in Google Auth Adapter ([GHSA-4q3h-vp4r-prv2](https://github.com/parse-community/parse-server/security/advisories/GHSA-4q3h-vp4r-prv2)) (#10073) 2026-02-23 22:04:35 +00:00
semantic-release-bot 035b9b549e chore(release): 8.6.2 [skip ci]
## [8.6.2](https://github.com/parse-community/parse-server/compare/8.6.1...8.6.2) (2025-12-16)

### Bug Fixes

* Server-Side Request Forgery (SSRF) in Instagram auth adapter [GHSA-3f5f-xgrj-97pf](https://github.com/parse-community/parse-server/security/advisories/GHSA-3f5f-xgrj-97pf) ([#9989](https://github.com/parse-community/parse-server/issues/9989)) ([155c6ad](https://github.com/parse-community/parse-server/commit/155c6ad92d2375652c9720d7deed129a9e8f74ff))
2025-12-16 01:24:04 +00:00
Manuel 155c6ad92d fix: Server-Side Request Forgery (SSRF) in Instagram auth adapter [GHSA-3f5f-xgrj-97pf](https://github.com/parse-community/parse-server/security/advisories/GHSA-3f5f-xgrj-97pf) (#9989) 2025-12-16 02:23:13 +01:00
semantic-release-bot 0b032a3f87 chore(release): 8.6.1 [skip ci]
## [8.6.1](https://github.com/parse-community/parse-server/compare/8.6.0...8.6.1) (2025-12-14)

### Bug Fixes

* Cross-Site Scripting (XSS) via HTML pages for password reset and email verification [GHSA-jhgf-2h8h-ggxv](https://github.com/parse-community/parse-server/security/advisories/GHSA-jhgf-2h8h-ggxv) ([#9986](https://github.com/parse-community/parse-server/issues/9986)) ([12d8b50](https://github.com/parse-community/parse-server/commit/12d8b502a2f99098d177d095842b07d55f62313a))
2025-12-14 15:06:59 +00:00
Manuel 12d8b502a2 fix: Cross-Site Scripting (XSS) via HTML pages for password reset and email verification [GHSA-jhgf-2h8h-ggxv](https://github.com/parse-community/parse-server/security/advisories/GHSA-jhgf-2h8h-ggxv) (#9986) 2025-12-14 16:06:02 +01:00
Manuel 9896817df6 ci: Update auto-release LTS branch (#9968) 2025-12-12 00:53:40 +01:00
semantic-release-bot 04cc78fc9d chore(release): 8.6.0 [skip ci]
# [8.6.0](https://github.com/parse-community/parse-server/compare/8.5.0...8.6.0) (2025-12-10)

### Bug Fixes

* Remove elevated permissions in GitHub CI performance benchmark ([#9966](https://github.com/parse-community/parse-server/issues/9966)) ([6b9f896](https://github.com/parse-community/parse-server/commit/6b9f8963cc3debf59cd9c5dfc5422aff9404ce9d))

### Features

* Add GraphQL query `cloudConfig` to retrieve and mutation `updateCloudConfig` to update Cloud Config ([#9947](https://github.com/parse-community/parse-server/issues/9947)) ([3ca85cd](https://github.com/parse-community/parse-server/commit/3ca85cd4a632f234c9d3d731331c0524dfe54075))
2025-12-10 22:42:55 +00:00
Manuel e3d27fea08 build: Release (#9967) 2025-12-10 23:41:40 +01:00
GitHub Actions 42723dbc66 empty commit to trigger CI 2025-12-10 22:40:56 +00:00
semantic-release-bot dcd05870fc chore(release): 8.6.0-alpha.2 [skip ci]
# [8.6.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.6.0-alpha.1...8.6.0-alpha.2) (2025-12-10)

### Bug Fixes

* Remove elevated permissions in GitHub CI performance benchmark ([#9966](https://github.com/parse-community/parse-server/issues/9966)) ([6b9f896](https://github.com/parse-community/parse-server/commit/6b9f8963cc3debf59cd9c5dfc5422aff9404ce9d))
2025-12-10 22:39:13 +00:00
Manuel 6b9f8963cc fix: Remove elevated permissions in GitHub CI performance benchmark (#9966) 2025-12-10 23:38:22 +01:00
dependabot[bot] e78e58d778 refactor: Bump jws (#9960) 2025-12-04 18:12:10 +01:00
semantic-release-bot 4c0987f64b chore(release): 8.6.0-alpha.1 [skip ci]
# [8.6.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.5.0...8.6.0-alpha.1) (2025-12-03)

### Features

* Add GraphQL query `cloudConfig` to retrieve and mutation `updateCloudConfig` to update Cloud Config ([#9947](https://github.com/parse-community/parse-server/issues/9947)) ([3ca85cd](https://github.com/parse-community/parse-server/commit/3ca85cd4a632f234c9d3d731331c0524dfe54075))
2025-12-03 18:56:27 +00:00
Lucas Coratger 3ca85cd4a6 feat: Add GraphQL query cloudConfig to retrieve and mutation updateCloudConfig to update Cloud Config (#9947) 2025-12-03 19:55:30 +01:00
dependabot[bot] 6d670131a0 refactor: Bump express (#9957) 2025-12-03 19:38:28 +01:00
Mattia Faraci f6ccef1d53 chore: Add objectParser for ObjectTypeAnnotation in Parse Server options (#9912) 2025-12-03 16:10:29 +01:00
dependabot[bot] 339b10c39b refactor: Bump body-parser from 2.2.0 to 2.2.1 (#9945) 2025-12-02 07:45:57 +01:00
semantic-release-bot b479102de0 chore(release): 8.5.0 [skip ci]
# [8.5.0](https://github.com/parse-community/parse-server/compare/8.4.0...8.5.0) (2025-12-01)

### Bug Fixes

* `GridFSBucketAdapter` throws when using some Parse Server specific options in MongoDB database options ([#9915](https://github.com/parse-community/parse-server/issues/9915)) ([d3d4003](https://github.com/parse-community/parse-server/commit/d3d4003570b9872f2b0f5a25fc06ce4c4132860d))
* Deprecation warning logged at server launch for nested Parse Server option even if option is explicitly set ([#9934](https://github.com/parse-community/parse-server/issues/9934)) ([c22cb0a](https://github.com/parse-community/parse-server/commit/c22cb0ae58e64cd0e4597ab9610d57a1155c44a2))
* Parse Server option `rateLimit.zone` does not use default value `ip` ([#9941](https://github.com/parse-community/parse-server/issues/9941)) ([12beb8f](https://github.com/parse-community/parse-server/commit/12beb8f6ee5d3002fec017bb4525eb3f1375f806))
* Queries with object field `authData.provider.id` are incorrectly transformed to `_auth_data_provider.id` for custom classes ([#9932](https://github.com/parse-community/parse-server/issues/9932)) ([7b9fa18](https://github.com/parse-community/parse-server/commit/7b9fa18f968ec084ea0b35dad2b5ba0451d59787))
* Race condition can cause multiple Apollo server initializations under load ([#9929](https://github.com/parse-community/parse-server/issues/9929)) ([7d5e9fc](https://github.com/parse-community/parse-server/commit/7d5e9fcf3ceb0abad8ab49c75bc26f521a0f1bde))
* Server internal error details leaking in error messages returned to clients ([#9937](https://github.com/parse-community/parse-server/issues/9937)) ([50edb5a](https://github.com/parse-community/parse-server/commit/50edb5ab4bb4a6ce474bfb7cf159d918933753b8))

### Features

* Add `beforePasswordResetRequest` hook ([#9906](https://github.com/parse-community/parse-server/issues/9906)) ([94cee5b](https://github.com/parse-community/parse-server/commit/94cee5bfafca10c914c73cf17fcdb627a9f0837b))
* Add MongoDB client event logging via database option `logClientEvents` ([#9914](https://github.com/parse-community/parse-server/issues/9914)) ([b760733](https://github.com/parse-community/parse-server/commit/b760733b98bcfc9c09ac9780066602e1fda108fe))
* Add Parse Server option `allowPublicExplain` to allow `Parse.Query.explain` without master key ([#9890](https://github.com/parse-community/parse-server/issues/9890)) ([4456b02](https://github.com/parse-community/parse-server/commit/4456b02280c2d8dd58b7250e9e67f1a8647b3452))
* Add Parse Server option `enableSanitizedErrorResponse` to remove detailed error messages from responses sent to clients ([#9944](https://github.com/parse-community/parse-server/issues/9944)) ([4752197](https://github.com/parse-community/parse-server/commit/47521974aeafcf41102be62f19612a4ab0a4837f))
* Add support for MongoDB driver options `serverSelectionTimeoutMS`, `maxIdleTimeMS`, `heartbeatFrequencyMS` ([#9910](https://github.com/parse-community/parse-server/issues/9910)) ([1b661e9](https://github.com/parse-community/parse-server/commit/1b661e98c86a1db79e076a7297cd9199a72ae1ac))
* Add support for more MongoDB driver options ([#9911](https://github.com/parse-community/parse-server/issues/9911)) ([cff451e](https://github.com/parse-community/parse-server/commit/cff451eabdc380affa600ed711de66f7bd1d00aa))
* Allow option `publicServerURL` to be set dynamically as asynchronous function ([#9803](https://github.com/parse-community/parse-server/issues/9803)) ([460a65c](https://github.com/parse-community/parse-server/commit/460a65cf612f4c86af8038cafcc7e7ffe9eb8440))
* Upgrade to parse 7.1.1 ([#9954](https://github.com/parse-community/parse-server/issues/9954)) ([fa57d69](https://github.com/parse-community/parse-server/commit/fa57d69cbec525189da98d7136c1c0e9eaf74338))
* Upgrade to parse 7.1.2 ([#9955](https://github.com/parse-community/parse-server/issues/9955)) ([5c644a5](https://github.com/parse-community/parse-server/commit/5c644a55ac25986f214b68ba4bcbe7a62ad6d6d1))

### Performance Improvements

* `Parse.Query.include` now fetches pointers at same level in parallel ([#9861](https://github.com/parse-community/parse-server/issues/9861)) ([dafea21](https://github.com/parse-community/parse-server/commit/dafea21eb39b0fdc2b52bb8a14f7b61e3f2b8d13))
* Remove unused dependencies ([#9943](https://github.com/parse-community/parse-server/issues/9943)) ([d4c6de0](https://github.com/parse-community/parse-server/commit/d4c6de0096b3ac95289c6bddfe25eb397d790e41))
* Upgrade MongoDB driver to 6.20.0 ([#9887](https://github.com/parse-community/parse-server/issues/9887)) ([3c9af48](https://github.com/parse-community/parse-server/commit/3c9af48edd999158443b797e388e29495953799e))
2025-12-01 19:54:33 +00:00
Manuel 5a1cdab753 build: Release (#9956) 2025-12-01 20:53:37 +01:00
GitHub Actions 77bcdfc04e empty commit to trigger CI 2025-12-01 19:21:23 +00:00
semantic-release-bot bdc71be9a3 chore(release): 8.5.0-alpha.18 [skip ci]
# [8.5.0-alpha.18](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.17...8.5.0-alpha.18) (2025-12-01)

### Features

* Upgrade to parse 7.1.2 ([#9955](https://github.com/parse-community/parse-server/issues/9955)) ([5c644a5](https://github.com/parse-community/parse-server/commit/5c644a55ac25986f214b68ba4bcbe7a62ad6d6d1))
2025-12-01 19:19:59 +00:00
Manuel 5c644a55ac feat: Upgrade to parse 7.1.2 (#9955) 2025-12-01 20:19:11 +01:00
semantic-release-bot 0e1cb3367e chore(release): 8.5.0-alpha.17 [skip ci]
# [8.5.0-alpha.17](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.16...8.5.0-alpha.17) (2025-12-01)

### Features

* Upgrade to parse 7.1.1 ([#9954](https://github.com/parse-community/parse-server/issues/9954)) ([fa57d69](https://github.com/parse-community/parse-server/commit/fa57d69cbec525189da98d7136c1c0e9eaf74338))
2025-12-01 18:12:18 +00:00
Manuel fa57d69cbe feat: Upgrade to parse 7.1.1 (#9954) 2025-12-01 19:11:20 +01:00
semantic-release-bot a906a11107 chore(release): 8.5.0-alpha.16 [skip ci]
# [8.5.0-alpha.16](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.15...8.5.0-alpha.16) (2025-11-28)

### Features

* Add Parse Server option `enableSanitizedErrorResponse` to remove detailed error messages from responses sent to clients ([#9944](https://github.com/parse-community/parse-server/issues/9944)) ([4752197](https://github.com/parse-community/parse-server/commit/47521974aeafcf41102be62f19612a4ab0a4837f))
2025-11-28 18:49:26 +00:00
Lucas Coratger 47521974ae feat: Add Parse Server option enableSanitizedErrorResponse to remove detailed error messages from responses sent to clients (#9944) 2025-11-28 19:48:35 +01:00
semantic-release-bot 73e78127c2 chore(release): 8.5.0-alpha.15 [skip ci]
# [8.5.0-alpha.15](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.14...8.5.0-alpha.15) (2025-11-23)

### Performance Improvements

* Remove unused dependencies ([#9943](https://github.com/parse-community/parse-server/issues/9943)) ([d4c6de0](https://github.com/parse-community/parse-server/commit/d4c6de0096b3ac95289c6bddfe25eb397d790e41))
2025-11-23 17:11:36 +00:00
Lucas Coratger d4c6de0096 perf: Remove unused dependencies (#9943) 2025-11-23 18:10:44 +01:00
semantic-release-bot 8aae732ace chore(release): 8.5.0-alpha.14 [skip ci]
# [8.5.0-alpha.14](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.13...8.5.0-alpha.14) (2025-11-23)

### Bug Fixes

* Parse Server option `rateLimit.zone` does not use default value `ip` ([#9941](https://github.com/parse-community/parse-server/issues/9941)) ([12beb8f](https://github.com/parse-community/parse-server/commit/12beb8f6ee5d3002fec017bb4525eb3f1375f806))
2025-11-23 13:10:13 +00:00
Manuel 12beb8f6ee fix: Parse Server option rateLimit.zone does not use default value ip (#9941) 2025-11-23 14:09:25 +01:00
semantic-release-bot 0ff97793cd chore(release): 8.5.0-alpha.13 [skip ci]
# [8.5.0-alpha.13](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.12...8.5.0-alpha.13) (2025-11-23)

### Bug Fixes

* Server internal error details leaking in error messages returned to clients ([#9937](https://github.com/parse-community/parse-server/issues/9937)) ([50edb5a](https://github.com/parse-community/parse-server/commit/50edb5ab4bb4a6ce474bfb7cf159d918933753b8))
2025-11-23 12:52:31 +00:00
Lucas Coratger 50edb5ab4b fix: Server internal error details leaking in error messages returned to clients (#9937) 2025-11-23 13:51:42 +01:00
Manuel 38c9d2e359 test: Add tests for Parse.Query.includeAll for circular and self-referencing pointers (#9936) 2025-11-23 13:16:22 +01:00
Lucas Coratger 69a925879e refactor: Add lint rules for no unused vars and unused import (#9940) 2025-11-22 22:12:34 +01:00
semantic-release-bot 9ed9af48d1 chore(release): 8.5.0-alpha.12 [skip ci]
# [8.5.0-alpha.12](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.11...8.5.0-alpha.12) (2025-11-19)

### Features

* Add `beforePasswordResetRequest` hook ([#9906](https://github.com/parse-community/parse-server/issues/9906)) ([94cee5b](https://github.com/parse-community/parse-server/commit/94cee5bfafca10c914c73cf17fcdb627a9f0837b))
2025-11-19 13:58:56 +00:00
Lucas Coratger 94cee5bfaf feat: Add beforePasswordResetRequest hook (#9906) 2025-11-19 14:57:28 +01:00
semantic-release-bot 50650a3626 chore(release): 8.5.0-alpha.11 [skip ci]
# [8.5.0-alpha.11](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.10...8.5.0-alpha.11) (2025-11-17)

### Bug Fixes

* Deprecation warning logged at server launch for nested Parse Server option even if option is explicitly set ([#9934](https://github.com/parse-community/parse-server/issues/9934)) ([c22cb0a](https://github.com/parse-community/parse-server/commit/c22cb0ae58e64cd0e4597ab9610d57a1155c44a2))
2025-11-17 18:44:26 +00:00
Manuel c22cb0ae58 fix: Deprecation warning logged at server launch for nested Parse Server option even if option is explicitly set (#9934) 2025-11-17 19:43:32 +01:00
dependabot[bot] 5e15403bc1 refactor: Bump js-yaml from 3.14.1 to 3.14.2 (#9933) 2025-11-17 18:17:44 +01:00
semantic-release-bot fcede163ca chore(release): 8.5.0-alpha.10 [skip ci]
# [8.5.0-alpha.10](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.9...8.5.0-alpha.10) (2025-11-17)

### Bug Fixes

* Queries with object field `authData.provider.id` are incorrectly transformed to `_auth_data_provider.id` for custom classes ([#9932](https://github.com/parse-community/parse-server/issues/9932)) ([7b9fa18](https://github.com/parse-community/parse-server/commit/7b9fa18f968ec084ea0b35dad2b5ba0451d59787))
2025-11-17 16:48:36 +00:00
Manuel 7b9fa18f96 fix: Queries with object field authData.provider.id are incorrectly transformed to _auth_data_provider.id for custom classes (#9932) 2025-11-17 17:47:39 +01:00
semantic-release-bot 8ff1d89ce2 chore(release): 8.5.0-alpha.9 [skip ci]
# [8.5.0-alpha.9](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.8...8.5.0-alpha.9) (2025-11-17)

### Bug Fixes

* Race condition can cause multiple Apollo server initializations under load ([#9929](https://github.com/parse-community/parse-server/issues/9929)) ([7d5e9fc](https://github.com/parse-community/parse-server/commit/7d5e9fcf3ceb0abad8ab49c75bc26f521a0f1bde))
2025-11-17 15:19:31 +00:00
Antoine Cormouls 7d5e9fcf3c fix: Race condition can cause multiple Apollo server initializations under load (#9929) 2025-11-17 16:18:39 +01:00
semantic-release-bot 306c5fd830 chore(release): 8.5.0-alpha.8 [skip ci]
# [8.5.0-alpha.8](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.7...8.5.0-alpha.8) (2025-11-17)

### Performance Improvements

* `Parse.Query.include` now fetches pointers at same level in parallel ([#9861](https://github.com/parse-community/parse-server/issues/9861)) ([dafea21](https://github.com/parse-community/parse-server/commit/dafea21eb39b0fdc2b52bb8a14f7b61e3f2b8d13))
2025-11-17 14:43:50 +00:00
Antoine Cormouls dafea21eb3 perf: Parse.Query.include now fetches pointers at same level in parallel (#9861) 2025-11-17 15:42:49 +01:00
Manuel 52f7c89f3f ci: Fix performance step in CI (#9931) 2025-11-17 01:14:29 +01:00
Manuel 133660fb52 ci: Fix performance step in CI (#9927) 2025-11-09 18:57:23 +01:00
Manuel 3cc8c1ae3e ci: Fix performance step in CI (#9926) 2025-11-09 13:36:10 +01:00
Manuel 36e166cc81 ci: Fix performance step in CI (#9925) 2025-11-09 13:30:23 +01:00
Manuel d94f348d86 ci: Cancel obsolete performance benchmark jobs (#9923) 2025-11-09 02:21:58 +01:00
Manuel 818824f6fc ci: Fix performance step in CI (#9922) 2025-11-09 02:18:20 +01:00
Manuel b73ebac5c9 ci: Fix performance step in CI (#9921) 2025-11-09 02:02:17 +01:00
Manuel a85ba199be ci: Fix performance step in CI missing permissions (#9918) 2025-11-08 21:34:07 +01:00
Manuel 06f25ff31a ci: Fix performance step in CI missing permissions (#9917) 2025-11-08 21:28:07 +01:00
Manuel 92788a19d3 ci: Add performance impact step to CI (#9916) 2025-11-08 21:21:43 +01:00
semantic-release-bot 76826447f8 chore(release): 8.5.0-alpha.7 [skip ci]
# [8.5.0-alpha.7](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.6...8.5.0-alpha.7) (2025-11-08)

### Performance Improvements

* Upgrade MongoDB driver to 6.20.0 ([#9887](https://github.com/parse-community/parse-server/issues/9887)) ([3c9af48](https://github.com/parse-community/parse-server/commit/3c9af48edd999158443b797e388e29495953799e))
2025-11-08 19:05:24 +00:00
Manuel 3c9af48edd perf: Upgrade MongoDB driver to 6.20.0 (#9887) 2025-11-08 20:04:31 +01:00
semantic-release-bot 9f1fc7cb8a chore(release): 8.5.0-alpha.6 [skip ci]
# [8.5.0-alpha.6](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.5...8.5.0-alpha.6) (2025-11-08)

### Bug Fixes

* `GridFSBucketAdapter` throws when using some Parse Server specific options in MongoDB database options ([#9915](https://github.com/parse-community/parse-server/issues/9915)) ([d3d4003](https://github.com/parse-community/parse-server/commit/d3d4003570b9872f2b0f5a25fc06ce4c4132860d))
2025-11-08 17:42:37 +00:00
Manuel d3d4003570 fix: GridFSBucketAdapter throws when using some Parse Server specific options in MongoDB database options (#9915) 2025-11-08 18:41:45 +01:00
semantic-release-bot 502a512028 chore(release): 8.5.0-alpha.5 [skip ci]
# [8.5.0-alpha.5](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.4...8.5.0-alpha.5) (2025-11-08)

### Features

* Add Parse Server option `allowPublicExplain` to allow `Parse.Query.explain` without master key ([#9890](https://github.com/parse-community/parse-server/issues/9890)) ([4456b02](https://github.com/parse-community/parse-server/commit/4456b02280c2d8dd58b7250e9e67f1a8647b3452))
2025-11-08 16:03:05 +00:00
Lucas Coratger 4456b02280 feat: Add Parse Server option allowPublicExplain to allow Parse.Query.explain without master key (#9890) 2025-11-08 17:02:13 +01:00
semantic-release-bot 15c8b1abed chore(release): 8.5.0-alpha.4 [skip ci]
# [8.5.0-alpha.4](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.3...8.5.0-alpha.4) (2025-11-08)

### Features

* Add MongoDB client event logging via database option `logClientEvents` ([#9914](https://github.com/parse-community/parse-server/issues/9914)) ([b760733](https://github.com/parse-community/parse-server/commit/b760733b98bcfc9c09ac9780066602e1fda108fe))
2025-11-08 14:49:18 +00:00
Manuel b760733b98 feat: Add MongoDB client event logging via database option logClientEvents (#9914) 2025-11-08 15:48:29 +01:00
semantic-release-bot 2424054221 chore(release): 8.5.0-alpha.3 [skip ci]
# [8.5.0-alpha.3](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.2...8.5.0-alpha.3) (2025-11-07)

### Features

* Add support for more MongoDB driver options ([#9911](https://github.com/parse-community/parse-server/issues/9911)) ([cff451e](https://github.com/parse-community/parse-server/commit/cff451eabdc380affa600ed711de66f7bd1d00aa))
2025-11-07 20:42:49 +00:00
Manuel cff451eabd feat: Add support for more MongoDB driver options (#9911) 2025-11-07 21:41:59 +01:00
semantic-release-bot 412406915f chore(release): 8.5.0-alpha.2 [skip ci]
# [8.5.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.1...8.5.0-alpha.2) (2025-11-07)

### Features

* Add support for MongoDB driver options `serverSelectionTimeoutMS`, `maxIdleTimeMS`, `heartbeatFrequencyMS` ([#9910](https://github.com/parse-community/parse-server/issues/9910)) ([1b661e9](https://github.com/parse-community/parse-server/commit/1b661e98c86a1db79e076a7297cd9199a72ae1ac))
2025-11-07 19:12:11 +00:00
Manuel 1b661e98c8 feat: Add support for MongoDB driver options serverSelectionTimeoutMS, maxIdleTimeMS, heartbeatFrequencyMS (#9910) 2025-11-07 20:11:12 +01:00
semantic-release-bot d5e7d6e0f6 chore(release): 8.5.0-alpha.1 [skip ci]
# [8.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.4.0...8.5.0-alpha.1) (2025-11-07)

### Features

* Allow option `publicServerURL` to be set dynamically as asynchronous function ([#9803](https://github.com/parse-community/parse-server/issues/9803)) ([460a65c](https://github.com/parse-community/parse-server/commit/460a65cf612f4c86af8038cafcc7e7ffe9eb8440))
2025-11-07 18:19:51 +00:00
Daniel 460a65cf61 feat: Allow option publicServerURL to be set dynamically as asynchronous function (#9803) 2025-11-07 19:18:58 +01:00
semantic-release-bot f27b050e4d chore(release): 8.4.0 [skip ci]
# [8.4.0](https://github.com/parse-community/parse-server/compare/8.3.0...8.4.0) (2025-11-05)

### Bug Fixes

* Add problematic MIME types to default value of Parse Server option `fileUpload.fileExtensions` ([#9902](https://github.com/parse-community/parse-server/issues/9902)) ([fa245cb](https://github.com/parse-community/parse-server/commit/fa245cbb5f5b7a0dad962b2ce0524fa4dafcb5f7))
* Uploading a file by providing an origin URL allows for Server-Side Request Forgery (SSRF); fixes vulnerability [GHSA-x4qj-2f4q-r4rx](https://github.com/parse-community/parse-server/security/advisories/GHSA-x4qj-2f4q-r4rx) ([#9903](https://github.com/parse-community/parse-server/issues/9903)) ([9776386](https://github.com/parse-community/parse-server/commit/97763863b72689a29ad7a311dfb590c3e3c50585))

### Features

* Add support for Node 24 ([#9901](https://github.com/parse-community/parse-server/issues/9901)) ([25dfe19](https://github.com/parse-community/parse-server/commit/25dfe19fef02fd44224e4a6d198584a694a1aa52))
2025-11-05 14:11:35 +00:00
Manuel 81b47f2eda build: Release (#9905) 2025-11-05 15:10:40 +01:00
GitHub Actions fbde4583ce empty commit to trigger CI 2025-11-05 13:54:40 +00:00
semantic-release-bot c70d543c56 chore(release): 8.4.0-alpha.2 [skip ci]
# [8.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.4.0-alpha.1...8.4.0-alpha.2) (2025-11-05)

### Bug Fixes

* Uploading a file by providing an origin URL allows for Server-Side Request Forgery (SSRF); fixes vulnerability [GHSA-x4qj-2f4q-r4rx](https://github.com/parse-community/parse-server/security/advisories/GHSA-x4qj-2f4q-r4rx) ([#9903](https://github.com/parse-community/parse-server/issues/9903)) ([9776386](https://github.com/parse-community/parse-server/commit/97763863b72689a29ad7a311dfb590c3e3c50585))
2025-11-05 13:41:15 +00:00
Manuel 97763863b7 fix: Uploading a file by providing an origin URL allows for Server-Side Request Forgery (SSRF); fixes vulnerability [GHSA-x4qj-2f4q-r4rx](https://github.com/parse-community/parse-server/security/advisories/GHSA-x4qj-2f4q-r4rx) (#9903) 2025-11-05 14:39:52 +01:00
semantic-release-bot 52bfb186fc chore(release): 8.4.0-alpha.1 [skip ci]
# [8.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.3.1-alpha.1...8.4.0-alpha.1) (2025-11-05)

### Features

* Add support for Node 24 ([#9901](https://github.com/parse-community/parse-server/issues/9901)) ([25dfe19](https://github.com/parse-community/parse-server/commit/25dfe19fef02fd44224e4a6d198584a694a1aa52))
2025-11-05 12:56:42 +00:00
Heinrich Filter 25dfe19fef feat: Add support for Node 24 (#9901) 2025-11-05 13:55:38 +01:00
semantic-release-bot 1f4f7129df chore(release): 8.3.1-alpha.1 [skip ci]
## [8.3.1-alpha.1](https://github.com/parse-community/parse-server/compare/8.3.0...8.3.1-alpha.1) (2025-11-05)

### Bug Fixes

* Add problematic MIME types to default value of Parse Server option `fileUpload.fileExtensions` ([#9902](https://github.com/parse-community/parse-server/issues/9902)) ([fa245cb](https://github.com/parse-community/parse-server/commit/fa245cbb5f5b7a0dad962b2ce0524fa4dafcb5f7))
2025-11-05 11:14:22 +00:00
Manuel fa245cbb5f fix: Add problematic MIME types to default value of Parse Server option fileUpload.fileExtensions (#9902) 2025-11-05 12:13:30 +01:00
Manuel e9fc20d224 docs: Fix docs generation (#9899) 2025-11-01 22:47:37 +01:00
semantic-release-bot 405a46bf5e chore(release): 8.3.0 [skip ci]
# [8.3.0](https://github.com/parse-community/parse-server/compare/8.2.5...8.3.0) (2025-11-01)

### Bug Fixes

* Error in `afterSave` trigger for `Parse.Role` due to `name` field ([#9883](https://github.com/parse-community/parse-server/issues/9883)) ([eb052d8](https://github.com/parse-community/parse-server/commit/eb052d8e6abe1ae32505fd068d5445eaf950a770))
* Indexes `_email_verify_token` for email verification and `_perishable_token` password reset are not created automatically ([#9893](https://github.com/parse-community/parse-server/issues/9893)) ([62dd3c5](https://github.com/parse-community/parse-server/commit/62dd3c565ab70765cb1c547996b616b72e9bb800))
* Security upgrade to parse 7.0.1 ([#9877](https://github.com/parse-community/parse-server/issues/9877)) ([abfa94c](https://github.com/parse-community/parse-server/commit/abfa94cd6de2c4e76337931c8ea8311c4ccf2a1a))
* Server URL verification before server is ready ([#9882](https://github.com/parse-community/parse-server/issues/9882)) ([178bd5c](https://github.com/parse-community/parse-server/commit/178bd5c5e258d9501c9ac4d35a3a105ab64be67e))
* Stale data read in validation query on `Parse.Object` update causes inconsistency between validation read and subsequent update write operation ([#9859](https://github.com/parse-community/parse-server/issues/9859)) ([f49efaf](https://github.com/parse-community/parse-server/commit/f49efaf5bb1d6b19f6d6712f7cdf073855c95c6e))
* Warning logged when setting option `databaseOptions.disableIndexFieldValidation` ([#9880](https://github.com/parse-community/parse-server/issues/9880)) ([1815b01](https://github.com/parse-community/parse-server/commit/1815b019b52565d2bc87be2596a49aea7600aeba))

### Features

* Add option `keepUnknownIndexes` to retain indexes which are not specified in schema ([#9857](https://github.com/parse-community/parse-server/issues/9857)) ([89fad46](https://github.com/parse-community/parse-server/commit/89fad468c3a43772879c06c4d939a83b72517a8e))
* Add options to skip automatic creation of internal database indexes on server start ([#9897](https://github.com/parse-community/parse-server/issues/9897)) ([ea91aca](https://github.com/parse-community/parse-server/commit/ea91aca1420c33e038516a321b2640709589f886))
* Add Parse Server option `verifyServerUrl` to disable server URL verification on server launch ([#9881](https://github.com/parse-community/parse-server/issues/9881)) ([b298ccc](https://github.com/parse-community/parse-server/commit/b298cccd9fb4f664b9d83894faad6d1ea7a3c964))
* Add regex option `u` for unicode support in `Parse.Query.matches` for MongoDB ([#9867](https://github.com/parse-community/parse-server/issues/9867)) ([7cb962a](https://github.com/parse-community/parse-server/commit/7cb962a02845f3dded61baffd84515f94b66ee50))
* Add request context middleware for config and dependency injection in hooks ([#8480](https://github.com/parse-community/parse-server/issues/8480)) ([64f104e](https://github.com/parse-community/parse-server/commit/64f104e5c5f8863098e801eee632c14fcbd9b6f9))
* Add support for Postgres 18 ([#9870](https://github.com/parse-community/parse-server/issues/9870)) ([d275c18](https://github.com/parse-community/parse-server/commit/d275c1806e0a5a037cc06cde7eefff3e12c91d7d))
* Allow returning objects in `Parse.Cloud.beforeFind` without invoking database query ([#9770](https://github.com/parse-community/parse-server/issues/9770)) ([0b47407](https://github.com/parse-community/parse-server/commit/0b4740714c29ba99672bc535619ee3516abd356f))
* Disable index-field validation to create index for fields that don't yet exist ([#8137](https://github.com/parse-community/parse-server/issues/8137)) ([1b23475](https://github.com/parse-community/parse-server/commit/1b2347524ca84ade0f6badf175a815fc8a7bef49))
2025-11-01 20:18:20 +00:00
Manuel 7a6acde6c5 build: Release (#9898) 2025-11-01 21:17:27 +01:00
GitHub Actions 0a25e2d62c empty commit to trigger CI 2025-11-01 19:26:14 +00:00
semantic-release-bot d1590bfaee chore(release): 8.3.0-alpha.14 [skip ci]
# [8.3.0-alpha.14](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.13...8.3.0-alpha.14) (2025-11-01)

### Features

* Add options to skip automatic creation of internal database indexes on server start ([#9897](https://github.com/parse-community/parse-server/issues/9897)) ([ea91aca](https://github.com/parse-community/parse-server/commit/ea91aca1420c33e038516a321b2640709589f886))
2025-11-01 17:23:42 +00:00
Manuel ea91aca142 feat: Add options to skip automatic creation of internal database indexes on server start (#9897) 2025-11-01 18:22:52 +01:00
semantic-release-bot 4f4580a083 chore(release): 8.3.0-alpha.13 [skip ci]
# [8.3.0-alpha.13](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.12...8.3.0-alpha.13) (2025-11-01)

### Bug Fixes

* Indexes `_email_verify_token` for email verification and `_perishable_token` password reset are not created automatically ([#9893](https://github.com/parse-community/parse-server/issues/9893)) ([62dd3c5](https://github.com/parse-community/parse-server/commit/62dd3c565ab70765cb1c547996b616b72e9bb800))
2025-11-01 12:53:21 +00:00
Manuel 62dd3c565a fix: Indexes _email_verify_token for email verification and _perishable_token password reset are not created automatically (#9893) 2025-11-01 13:52:23 +01:00
semantic-release-bot 00f8d4cda9 chore(release): 8.3.0-alpha.12 [skip ci]
# [8.3.0-alpha.12](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.11...8.3.0-alpha.12) (2025-10-25)

### Features

* Add Parse Server option `verifyServerUrl` to disable server URL verification on server launch ([#9881](https://github.com/parse-community/parse-server/issues/9881)) ([b298ccc](https://github.com/parse-community/parse-server/commit/b298cccd9fb4f664b9d83894faad6d1ea7a3c964))
2025-10-25 16:02:58 +00:00
Antoine Cormouls b298cccd9f feat: Add Parse Server option verifyServerUrl to disable server URL verification on server launch (#9881) 2025-10-25 18:01:58 +02:00
semantic-release-bot a3ac82fc54 chore(release): 8.3.0-alpha.11 [skip ci]
# [8.3.0-alpha.11](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.10...8.3.0-alpha.11) (2025-10-24)

### Bug Fixes

* Stale data read in validation query on `Parse.Object` update causes inconsistency between validation read and subsequent update write operation ([#9859](https://github.com/parse-community/parse-server/issues/9859)) ([f49efaf](https://github.com/parse-community/parse-server/commit/f49efaf5bb1d6b19f6d6712f7cdf073855c95c6e))
2025-10-24 18:59:41 +00:00
mavriel@gmail.com f49efaf5bb fix: Stale data read in validation query on Parse.Object update causes inconsistency between validation read and subsequent update write operation (#9859) 2025-10-24 20:58:44 +02:00
semantic-release-bot 8006a9e2c1 chore(release): 8.3.0-alpha.10 [skip ci]
# [8.3.0-alpha.10](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.9...8.3.0-alpha.10) (2025-10-22)

### Bug Fixes

* Error in `afterSave` trigger for `Parse.Role` due to `name` field ([#9883](https://github.com/parse-community/parse-server/issues/9883)) ([eb052d8](https://github.com/parse-community/parse-server/commit/eb052d8e6abe1ae32505fd068d5445eaf950a770))
2025-10-22 12:13:47 +00:00
Antoine Cormouls eb052d8e6a fix: Error in afterSave trigger for Parse.Role due to name field (#9883) 2025-10-22 14:12:51 +02:00
semantic-release-bot 1de329d900 chore(release): 8.3.0-alpha.9 [skip ci]
# [8.3.0-alpha.9](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.8...8.3.0-alpha.9) (2025-10-19)

### Bug Fixes

* Server URL verification before server is ready ([#9882](https://github.com/parse-community/parse-server/issues/9882)) ([178bd5c](https://github.com/parse-community/parse-server/commit/178bd5c5e258d9501c9ac4d35a3a105ab64be67e))
2025-10-19 19:26:36 +00:00
Manuel 178bd5c5e2 fix: Server URL verification before server is ready (#9882) 2025-10-19 21:25:46 +02:00
semantic-release-bot 115e76e8ad chore(release): 8.3.0-alpha.8 [skip ci]
# [8.3.0-alpha.8](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.7...8.3.0-alpha.8) (2025-10-16)

### Bug Fixes

* Warning logged when setting option `databaseOptions.disableIndexFieldValidation` ([#9880](https://github.com/parse-community/parse-server/issues/9880)) ([1815b01](https://github.com/parse-community/parse-server/commit/1815b019b52565d2bc87be2596a49aea7600aeba))
2025-10-16 07:30:34 +00:00
Antoine Cormouls 1815b019b5 fix: Warning logged when setting option databaseOptions.disableIndexFieldValidation (#9880) 2025-10-16 09:29:02 +02:00
semantic-release-bot 3f0ec42240 chore(release): 8.3.0-alpha.7 [skip ci]
# [8.3.0-alpha.7](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.6...8.3.0-alpha.7) (2025-10-15)

### Bug Fixes

* Security upgrade to parse 7.0.1 ([#9877](https://github.com/parse-community/parse-server/issues/9877)) ([abfa94c](https://github.com/parse-community/parse-server/commit/abfa94cd6de2c4e76337931c8ea8311c4ccf2a1a))
2025-10-15 16:40:35 +00:00
Antoine Cormouls abfa94cd6d fix: Security upgrade to parse 7.0.1 (#9877) 2025-10-15 18:39:37 +02:00
semantic-release-bot 84cebd439e chore(release): 8.3.0-alpha.6 [skip ci]
# [8.3.0-alpha.6](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.5...8.3.0-alpha.6) (2025-10-14)

### Features

* Add request context middleware for config and dependency injection in hooks ([#8480](https://github.com/parse-community/parse-server/issues/8480)) ([64f104e](https://github.com/parse-community/parse-server/commit/64f104e5c5f8863098e801eee632c14fcbd9b6f9))
2025-10-14 18:17:28 +00:00
Antoine Cormouls 64f104e5c5 feat: Add request context middleware for config and dependency injection in hooks (#8480) 2025-10-14 20:16:31 +02:00
semantic-release-bot e704de83e6 chore(release): 8.3.0-alpha.5 [skip ci]
# [8.3.0-alpha.5](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.4...8.3.0-alpha.5) (2025-10-14)

### Features

* Allow returning objects in `Parse.Cloud.beforeFind` without invoking database query ([#9770](https://github.com/parse-community/parse-server/issues/9770)) ([0b47407](https://github.com/parse-community/parse-server/commit/0b4740714c29ba99672bc535619ee3516abd356f))
2025-10-14 16:14:19 +00:00
EmpiDev 0b4740714c feat: Allow returning objects in Parse.Cloud.beforeFind without invoking database query (#9770) 2025-10-14 18:13:28 +02:00
semantic-release-bot 0b606ae9c6 chore(release): 8.3.0-alpha.4 [skip ci]
# [8.3.0-alpha.4](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.3...8.3.0-alpha.4) (2025-10-09)

### Features

* Disable index-field validation to create index for fields that don't yet exist ([#8137](https://github.com/parse-community/parse-server/issues/8137)) ([1b23475](https://github.com/parse-community/parse-server/commit/1b2347524ca84ade0f6badf175a815fc8a7bef49))
2025-10-09 22:05:09 +00:00
Antoine Cormouls 1b2347524c feat: Disable index-field validation to create index for fields that don't yet exist (#8137) 2025-10-10 00:03:52 +02:00
Corey f024d532f0 refactor: Upgrade pg-promise to 12.2.0 (#9874) 2025-10-09 00:19:46 +02:00
semantic-release-bot be362fe59d chore(release): 8.3.0-alpha.3 [skip ci]
# [8.3.0-alpha.3](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.2...8.3.0-alpha.3) (2025-10-07)

### Features

* Add support for Postgres 18 ([#9870](https://github.com/parse-community/parse-server/issues/9870)) ([d275c18](https://github.com/parse-community/parse-server/commit/d275c1806e0a5a037cc06cde7eefff3e12c91d7d))
2025-10-07 10:03:57 +00:00
Corey d275c1806e feat: Add support for Postgres 18 (#9870) 2025-10-07 12:02:58 +02:00
semantic-release-bot f62da3f3c5 chore(release): 8.3.0-alpha.2 [skip ci]
# [8.3.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.3.0-alpha.1...8.3.0-alpha.2) (2025-10-03)

### Features

* Add regex option `u` for unicode support in `Parse.Query.matches` for MongoDB ([#9867](https://github.com/parse-community/parse-server/issues/9867)) ([7cb962a](https://github.com/parse-community/parse-server/commit/7cb962a02845f3dded61baffd84515f94b66ee50))
2025-10-03 14:39:31 +00:00
Manuel 7cb962a028 feat: Add regex option u for unicode support in Parse.Query.matches for MongoDB (#9867) 2025-10-03 16:38:41 +02:00
semantic-release-bot f755a5df21 chore(release): 8.3.0-alpha.1 [skip ci]
# [8.3.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.5...8.3.0-alpha.1) (2025-10-03)

### Features

* Add option `keepUnknownIndexes` to retain indexes which are not specified in schema ([#9857](https://github.com/parse-community/parse-server/issues/9857)) ([89fad46](https://github.com/parse-community/parse-server/commit/89fad468c3a43772879c06c4d939a83b72517a8e))
2025-10-03 12:36:25 +00:00
Rahul Lanjewar 89fad468c3 feat: Add option keepUnknownIndexes to retain indexes which are not specified in schema (#9857) 2025-10-03 14:35:34 +02:00
semantic-release-bot b7faabb569 chore(release): 8.2.5 [skip ci]
## [8.2.5](https://github.com/parse-community/parse-server/compare/8.2.4...8.2.5) (2025-10-02)

### Bug Fixes

* GraphQL playground shows blank page ([#9858](https://github.com/parse-community/parse-server/issues/9858)) ([7b5395c](https://github.com/parse-community/parse-server/commit/7b5395c5d481235c022d96603280672366a50715))
2025-10-02 13:28:25 +00:00
Manuel 3c7c5e1a78 build: Release (#9863) 2025-10-02 15:27:28 +02:00
GitHub Actions fe4ba57892 empty commit to trigger CI 2025-10-01 00:17:22 +00:00
Antoine Cormouls 389de8426c ci: Fix MongoDB test instance not terminated after running tests (#9860) 2025-09-30 13:42:51 +02:00
semantic-release-bot aad8ff9326 chore(release): 8.2.5-alpha.1 [skip ci]
## [8.2.5-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.4...8.2.5-alpha.1) (2025-09-21)

### Bug Fixes

* GraphQL playground shows blank page ([#9858](https://github.com/parse-community/parse-server/issues/9858)) ([7b5395c](https://github.com/parse-community/parse-server/commit/7b5395c5d481235c022d96603280672366a50715))
2025-09-21 15:46:01 +00:00
Alan Maulana Rahman 7b5395c5d4 fix: GraphQL playground shows blank page (#9858) 2025-09-21 17:45:07 +02:00
dependabot[bot] 82fdb0d95a refactor: Bump brace-expansion from 1.1.11 to 1.1.12 (#9854) 2025-09-05 11:02:40 +02:00
semantic-release-bot 43cb65ff90 chore(release): 8.2.4 [skip ci]
## [8.2.4](https://github.com/parse-community/parse-server/compare/8.2.3...8.2.4) (2025-09-01)

### Bug Fixes

* Security upgrade form-data from 4.0.3 to 4.0.4 ([#9829](https://github.com/parse-community/parse-server/issues/9829)) ([c2c593f](https://github.com/parse-community/parse-server/commit/c2c593f437c33f37101b4f3bb1287eef31dbbc3b))
2025-09-01 21:06:42 +00:00
Manuel e6283c3ca3 build: Release (#9851) 2025-09-01 23:05:34 +02:00
GitHub Actions b71a3106ce empty commit to trigger CI 2025-09-01 00:18:33 +00:00
dependabot[bot] 4b3f10b2ab refactor: Bump sha.js from 2.4.11 to 2.4.12 (#9845) 2025-08-24 13:55:22 +02:00
dependabot[bot] 587abdd45f refactor: Bump @eslint/plugin-kit from 0.3.1 to 0.3.4 (#9834) 2025-08-02 19:37:52 +02:00
semantic-release-bot 743484768b chore(release): 8.2.4-alpha.1 [skip ci]
## [8.2.4-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.3...8.2.4-alpha.1) (2025-08-02)

### Bug Fixes

* Security upgrade form-data from 4.0.3 to 4.0.4 ([#9829](https://github.com/parse-community/parse-server/issues/9829)) ([c2c593f](https://github.com/parse-community/parse-server/commit/c2c593f437c33f37101b4f3bb1287eef31dbbc3b))
2025-08-02 08:05:36 +00:00
dependabot[bot] c2c593f437 fix: Security upgrade form-data from 4.0.3 to 4.0.4 (#9829) 2025-08-02 10:04:39 +02:00
semantic-release-bot 1a24ede388 chore(release): 8.2.3 [skip ci]
## [8.2.3](https://github.com/parse-community/parse-server/compare/8.2.2...8.2.3) (2025-08-01)

### Bug Fixes

* MongoDB aggregation pipeline with `$dateSubtract` from `$$NOW` returns no results ([#9822](https://github.com/parse-community/parse-server/issues/9822)) ([847a274](https://github.com/parse-community/parse-server/commit/847a274cdb8c22f8e0fc249162e5e2c9e29a594a))
2025-08-01 10:07:10 +00:00
Manuel 080610ac5f build: Release (#9836) 2025-08-01 12:05:47 +02:00
GitHub Actions a09f751c14 empty commit to trigger CI 2025-08-01 00:19:22 +00:00
Parse Platform 3d8dc5fa0d refactor: Upgrade @babel/eslint-parser from 7.27.1 to 7.28.0 (#9835) 2025-07-30 00:37:51 +02:00
Parse Platform 4e301a5fff refactor: Upgrade express-rate-limit from 7.5.0 to 7.5.1 (#9824) 2025-07-18 01:28:11 +02:00
Parse Platform dfffc14a54 refactor: Upgrade pg-promise from 11.13.0 to 11.14.0 (#9825) 2025-07-15 15:37:21 +02:00
semantic-release-bot 9c6d7ab4f1 chore(release): 8.2.3-alpha.1 [skip ci]
## [8.2.3-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.2...8.2.3-alpha.1) (2025-07-13)

### Bug Fixes

* MongoDB aggregation pipeline with `$dateSubtract` from `$$NOW` returns no results ([#9822](https://github.com/parse-community/parse-server/issues/9822)) ([847a274](https://github.com/parse-community/parse-server/commit/847a274cdb8c22f8e0fc249162e5e2c9e29a594a))
2025-07-13 00:44:59 +00:00
Manuel 847a274cdb fix: MongoDB aggregation pipeline with $dateSubtract from $$NOW returns no results (#9822) 2025-07-13 02:44:08 +02:00
semantic-release-bot e3f5ae0be7 chore(release): 8.2.2 [skip ci]
## [8.2.2](https://github.com/parse-community/parse-server/compare/8.2.1...8.2.2) (2025-07-10)

### Bug Fixes

* Data schema exposed via GraphQL API public introspection (GHSA-48q3-prgv-gm4w) ([#9819](https://github.com/parse-community/parse-server/issues/9819)) ([c58b2eb](https://github.com/parse-community/parse-server/commit/c58b2eb6eb48af9d3c2e69b4829810a021347b40))
2025-07-10 02:42:31 +00:00
Manuel 3b8b3cb3dc build: Release (#9821) 2025-07-10 04:41:40 +02:00
Manuel e514070a64 Merge branch 'release' into build/release-20250710 2025-07-10 04:32:10 +02:00
GitHub Actions 7a08c2da2d empty commit to trigger CI 2025-07-10 02:31:18 +00:00
semantic-release-bot ceb92ed289 chore(release): 8.2.2-alpha.1 [skip ci]
## [8.2.2-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.1...8.2.2-alpha.1) (2025-07-10)

### Bug Fixes

* Data schema exposed via GraphQL API public introspection (GHSA-48q3-prgv-gm4w) ([#9819](https://github.com/parse-community/parse-server/issues/9819)) ([c58b2eb](https://github.com/parse-community/parse-server/commit/c58b2eb6eb48af9d3c2e69b4829810a021347b40))
2025-07-10 02:26:16 +00:00
Manuel c58b2eb6eb fix: Data schema exposed via GraphQL API public introspection (GHSA-48q3-prgv-gm4w) (#9819) 2025-07-10 04:25:09 +02:00
Manuel 2c29756038 refactor: Add a few lint rules to test files in /spec (#9815) 2025-07-04 20:24:08 +02:00
Manuel f11255da05 build: Release (#9814) 2025-07-01 18:44:19 +02:00
GitHub Actions 101a71d38e empty commit to trigger CI 2025-07-01 00:18:32 +00:00
Manuel 207d241b39 docs: Remove unsupported MongoDB versions from README (#9804) 2025-06-22 14:17:37 +02:00
Parse Platform d14a723191 refactor: Upgrade @apollo/server from 4.12.0 to 4.12.1 (#9791) 2025-06-18 00:00:47 +02:00
dependabot[bot] d4ef1c8bf0 refactor: Bump @babel/core from 7.27.3 to 7.27.4 (#9793) 2025-06-14 01:42:42 +02:00
dependabot[bot] 1ae3176172 refactor: Bump form-data from 4.0.2 to 4.0.3 (#9790) 2025-06-09 18:35:08 +02:00
dependabot[bot] 4626d35aa6 refactor: Bump mongodb from 6.16.0 to 6.17.0 (#9788) 2025-06-07 17:19:46 +02:00
dependabot[bot] e707d6f92d refactor: Bump jasmine from 5.6.0 to 5.7.1 (#9784) 2025-06-06 20:10:17 +02:00
dependabot[bot] 451858654e refactor: Bump typescript-eslint from 8.33.0 to 8.33.1 (#9787) 2025-06-05 14:44:44 +02:00
dependabot[bot] ea95f7d911 refactor: Bump lint-staged from 15.5.1 to 16.1.0 (#9783) 2025-06-05 11:56:27 +02:00
dependabot[bot] a513d8e6eb refactor: Bump mongodb-runner from 5.8.2 to 5.8.3 (#9782) 2025-06-02 14:46:02 +02:00
semantic-release-bot a528ab6bea chore(release): 8.2.1 [skip ci]
## [8.2.1](https://github.com/parse-community/parse-server/compare/8.2.0...8.2.1) (2025-06-01)

### Bug Fixes

* `Parse.Query.containedIn` and `matchesQuery` do not work with nested objects ([#9738](https://github.com/parse-community/parse-server/issues/9738)) ([0db3a6f](https://github.com/parse-community/parse-server/commit/0db3a6ff27a129427770e314a792cc586e4255b5))

### Performance Improvements

* Remove saving Parse Cloud Job request parameters in internal collection `_JobStatus` ([#8343](https://github.com/parse-community/parse-server/issues/8343)) ([e98733c](https://github.com/parse-community/parse-server/commit/e98733cbac9451521a3acc388d2f9d29eb4610e0))
2025-06-01 15:10:52 +00:00
Manuel bb0c35aa20 build: Release (#9781) 2025-06-01 17:10:03 +02:00
GitHub Actions 4191e85c7b empty commit to trigger CI 2025-06-01 00:19:37 +00:00
dependabot[bot] ab753cf9e2 refactor: Bump typescript-eslint from 8.29.0 to 8.33.0 (#9779) 2025-05-30 20:36:48 +02:00
dependabot[bot] 864f7cd431 refactor: Bump ws from 8.18.1 to 8.18.2 (#9780) 2025-05-30 18:31:10 +02:00
dependabot[bot] 14627dbea4 refactor: Bump semantic-release from 24.2.3 to 24.2.5 (#9777) 2025-05-29 22:30:46 +02:00
dependabot[bot] 1922fe5f06 refactor: Bump eslint from 9.25.1 to 9.27.0 (#9776) 2025-05-29 06:27:54 +02:00
dependabot[bot] 02188d9721 refactor: Bump @babel/core from 7.27.1 to 7.27.3 (#9771) 2025-05-27 16:52:49 +02:00
dependabot[bot] 40bad266b4 refactor: Bump globals from 16.1.0 to 16.2.0 (#9767) 2025-05-26 17:27:25 +02:00
dependabot[bot] 44b42ccea2 refactor: Bump @apollo/client from 3.13.7 to 3.13.8 (#9762) 2025-05-25 19:53:50 +02:00
dependabot[bot] f3f28f8f5e refactor: Bump flow-bin from 0.266.1 to 0.271.0 (#9760) 2025-05-17 00:58:54 +02:00
dependabot[bot] 349625beb2 refactor: Bump yaml from 2.7.1 to 2.8.0 (#9759) 2025-05-15 14:25:58 +02:00
semantic-release-bot 4e1f95c1c0 chore(release): 8.2.1-alpha.2 [skip ci]
## [8.2.1-alpha.2](https://github.com/parse-community/parse-server/compare/8.2.1-alpha.1...8.2.1-alpha.2) (2025-05-14)

### Performance Improvements

* Remove saving Parse Cloud Job request parameters in internal collection `_JobStatus` ([#8343](https://github.com/parse-community/parse-server/issues/8343)) ([e98733c](https://github.com/parse-community/parse-server/commit/e98733cbac9451521a3acc388d2f9d29eb4610e0))
2025-05-14 19:25:49 +00:00
Thomas Foricher e98733cbac perf: Remove saving Parse Cloud Job request parameters in internal collection _JobStatus (#8343) 2025-05-14 21:24:56 +02:00
dependabot[bot] 084ac5b90d refactor: Bump @babel/preset-env from 7.26.9 to 7.27.2 (#9758) 2025-05-14 13:38:50 +02:00
dependabot[bot] c96578686a refactor: Bump semver from 7.7.1 to 7.7.2 (#9756) 2025-05-14 11:16:31 +02:00
dependabot[bot] 505a37a6f5 refactor: Bump globals from 16.0.0 to 16.1.0 (#9755) 2025-05-12 14:34:34 +02:00
dependabot[bot] 13c1dffa57 refactor: Bump @babel/eslint-parser from 7.27.0 to 7.27.1 (#9754) 2025-05-10 02:39:07 +02:00
dependabot[bot] b537e5a7d7 refactor: Bump @babel/core from 7.26.10 to 7.27.1 (#9753) 2025-05-07 22:52:38 +02:00
dependabot[bot] f059b9b954 refactor: Bump graphql from 16.10.0 to 16.11.0 (#9751) 2025-05-06 17:29:00 +02:00
dependabot[bot] aba60c2b59 refactor: Bump @babel/preset-typescript from 7.27.0 to 7.27.1 (#9748) 2025-05-05 22:03:34 +02:00
dependabot[bot] 06b4f50085 refactor: Bump @semantic-release/github from 11.0.1 to 11.0.2 (#9749) 2025-05-05 21:35:44 +02:00
semantic-release-bot 560beeae6c chore(release): 8.2.1-alpha.1 [skip ci]
## [8.2.1-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.0...8.2.1-alpha.1) (2025-05-03)

### Bug Fixes

* `Parse.Query.containedIn` and `matchesQuery` do not work with nested objects ([#9738](https://github.com/parse-community/parse-server/issues/9738)) ([0db3a6f](https://github.com/parse-community/parse-server/commit/0db3a6ff27a129427770e314a792cc586e4255b5))
2025-05-03 10:53:19 +00:00
Rahul Lanjewar 0db3a6ff27 fix: Parse.Query.containedIn and matchesQuery do not work with nested objects (#9738) 2025-05-03 12:52:31 +02:00
dependabot[bot] 3271e2aa26 refactor: Bump eslint from 9.23.0 to 9.25.1 (#9746) 2025-05-02 22:04:03 +01:00
dependabot[bot] bdd8db40e7 refactor: Bump mongodb from 6.15.0 to 6.16.0 (#9745) 2025-05-02 16:44:32 +01:00
semantic-release-bot 7290525cf5 chore(release): 8.2.0 [skip ci]
# [8.2.0](https://github.com/parse-community/parse-server/compare/8.1.0...8.2.0) (2025-05-01)

### Features

* Add TypeScript definitions ([#9693](https://github.com/parse-community/parse-server/issues/9693)) ([e86718f](https://github.com/parse-community/parse-server/commit/e86718fc59c7c8e6f3c6abd0feb7d1a68ca76c23))

### Performance Improvements

* Add details to error message in `Parse.Query.aggregate` ([#9689](https://github.com/parse-community/parse-server/issues/9689)) ([9de6999](https://github.com/parse-community/parse-server/commit/9de6999e257d839b68bbca282447777edfdb1ddf))
2025-05-01 10:10:31 +00:00
Parse Platform a8d36b813a build: Release (#9747) 2025-05-01 11:09:42 +01:00
GitHub Actions 23046ad394 empty commit to trigger CI 2025-05-01 00:17:09 +00:00
dependabot[bot] ef665a60b3 refactor: Bump typescript from 5.8.2 to 5.8.3 (#9708) 2025-04-30 02:03:51 +01:00
Parse Platform e556812d06 refactor: Upgrade pg-monitor from 2.1.0 to 3.0.0 (#9736) 2025-04-29 12:46:09 +01:00
dependabot[bot] 1f9df00dcf refactor: Bump lint-staged from 15.5.0 to 15.5.1 (#9724) 2025-04-19 01:07:41 +01:00
dependabot[bot] 9a2cffe975 refactor: Bump @apollo/client from 3.13.4 to 3.13.7 (#9719) 2025-04-17 19:55:21 +01:00
Diamond Lewis ed69e03acf ci: Fix flaky sendVerificationEmail tests (#9692) 2025-04-15 17:25:42 +01:00
dependabot[bot] 788532bd39 refactor: Bump otpauth from 9.3.6 to 9.4.0 (#9710) 2025-04-15 17:23:40 +01:00
semantic-release-bot 30a4848eb8 chore(release): 8.2.0-alpha.1 [skip ci]
# [8.2.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.1.1-alpha.1...8.2.0-alpha.1) (2025-04-15)

### Features

* Add TypeScript definitions ([#9693](https://github.com/parse-community/parse-server/issues/9693)) ([e86718f](https://github.com/parse-community/parse-server/commit/e86718fc59c7c8e6f3c6abd0feb7d1a68ca76c23))
2025-04-15 12:00:48 +00:00
Diamond Lewis e86718fc59 feat: Add TypeScript definitions (#9693) 2025-04-15 12:59:58 +01:00
dependabot[bot] 39ef22d5c9 refactor: Bump m from 1.9.0 to 1.9.1 (#9707) 2025-04-14 18:43:05 +01:00
dependabot[bot] f363a6e471 refactor: Bump mongodb-runner from 5.8.1 to 5.8.2 (#9705) 2025-04-13 15:25:31 +01:00
dependabot[bot] 32f4a3864a refactor: Bump @apollo/server from 4.11.3 to 4.12.0 (#9706) 2025-04-12 02:27:33 +01:00
dependabot[bot] 59262961c9 refactor: Bump parse from 6.1.0 to 6.1.1 (#9703) 2025-04-10 20:40:14 +02:00
dependabot[bot] 7c2ab2d0c0 refactor: Bump all-node-versions from 12.1.0 to 13.0.1 (#9704) 2025-04-10 16:14:07 +02:00
dependabot[bot] 77f93bf0a2 refactor: Bump flow-bin from 0.119.1 to 0.266.1 (#9700) 2025-04-09 19:26:26 +01:00
dependabot[bot] 5f2cbd4a5b refactor: Bump express from 5.0.1 to 5.1.0 (#9702) 2025-04-09 18:15:56 +01:00
dependabot[bot] a4147bed24 refactor: Bump @babel/core from 7.26.8 to 7.26.10 (#9701) 2025-04-09 11:49:17 +02:00
Parse Platform c709729098 refactor: Upgrade @graphql-tools/utils from 10.8.4 to 10.8.6 (#9699) 2025-04-08 12:45:54 +02:00
semantic-release-bot c7695c4e94 chore(release): 8.1.1-alpha.1 [skip ci]
## [8.1.1-alpha.1](https://github.com/parse-community/parse-server/compare/8.1.0...8.1.1-alpha.1) (2025-04-07)

### Performance Improvements

* Add details to error message in `Parse.Query.aggregate` ([#9689](https://github.com/parse-community/parse-server/issues/9689)) ([9de6999](https://github.com/parse-community/parse-server/commit/9de6999e257d839b68bbca282447777edfdb1ddf))
2025-04-07 19:55:05 +00:00
Diamond Lewis 9de6999e25 perf: Add details to error message in Parse.Query.aggregate (#9689) 2025-04-07 21:54:18 +02:00
Parse Platform 9d8d494782 refactor: Upgrade bcryptjs from 2.4.3 to 3.0.2 (#9677) 2025-04-07 18:12:06 +02:00
dependabot[bot] 2f2a92ad5e refactor: Bump mongodb-runner from 5.8.0 to 5.8.1 (#9698) 2025-04-07 16:02:57 +02:00
dependabot[bot] 177de4d0ba refactor: Bump semantic-release from 24.2.1 to 24.2.3 (#9696) 2025-04-07 15:21:24 +02:00
dependabot[bot] 2be9429ecc refactor: Bump mime from 4.0.6 to 4.0.7 (#9697)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 15:05:38 +02:00
Diamond Lewis af40af51f3 ci: Fix flaky LiveQuery tests (#9694) 2025-04-07 04:01:36 +02:00
dependabot[bot] c7871e25aa refactor: Bump yaml from 2.7.0 to 2.7.1 (#9687) 2025-04-06 23:19:08 +02:00
dependabot[bot] 7e64eb74d7 refactor: Bump @babel/eslint-parser from 7.26.10 to 7.27.0 (#9691) 2025-04-06 22:36:35 +02:00
semantic-release-bot 4fb5bd7b5a chore(release): 8.1.0 [skip ci]
# [8.1.0](https://github.com/parse-community/parse-server/compare/8.0.2...8.1.0) (2025-04-04)

### Bug Fixes

* Parse Server doesn't shutdown gracefully ([#9634](https://github.com/parse-community/parse-server/issues/9634)) ([aed918d](https://github.com/parse-community/parse-server/commit/aed918d3109e739f7231d481b5f48c68fc01cf04))

### Features

* Add Cloud Code triggers `Parse.Cloud.beforeFind(Parse.File)`and `Parse.Cloud.afterFind(Parse.File)` ([#8700](https://github.com/parse-community/parse-server/issues/8700)) ([b2beaa8](https://github.com/parse-community/parse-server/commit/b2beaa86ff543a7aa4ad274c7a23bc4aa302c3fa))
* Add default ACL ([#8701](https://github.com/parse-community/parse-server/issues/8701)) ([12b5d78](https://github.com/parse-community/parse-server/commit/12b5d781dc3f8c43c0c566dffa9308d02a7d8043))
* Upgrade Parse JS SDK from 6.0.0 to 6.1.0 ([#9686](https://github.com/parse-community/parse-server/issues/9686)) ([f49c371](https://github.com/parse-community/parse-server/commit/f49c371c1373d41e68b091e65f33a71ff6fc6dd0))
2025-04-04 02:25:11 +00:00
Manuel d43517fadf build: Release (#9695) 2025-04-04 03:24:03 +01:00
GitHub Actions 4352accfb7 empty commit to trigger CI 2025-04-04 02:17:09 +00:00
dependabot[bot] 257be69128 refactor: Bump @babel/preset-env from 7.26.0 to 7.26.9 (#9683) 2025-04-02 01:16:31 +01:00
semantic-release-bot 5dbd254ce2 chore(release): 8.1.0-alpha.4 [skip ci]
# [8.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/8.1.0-alpha.3...8.1.0-alpha.4) (2025-04-01)

### Features

* Upgrade Parse JS SDK from 6.0.0 to 6.1.0 ([#9686](https://github.com/parse-community/parse-server/issues/9686)) ([f49c371](https://github.com/parse-community/parse-server/commit/f49c371c1373d41e68b091e65f33a71ff6fc6dd0))
2025-04-01 23:10:42 +00:00
Daniel f49c371c13 feat: Upgrade Parse JS SDK from 6.0.0 to 6.1.0 (#9686) 2025-04-02 00:09:53 +01:00
Manuel a9176d533d docs: Remove outdated code examples (#9685) 2025-03-31 02:11:34 +02:00
dependabot[bot] b559fbf4a2 refactor: Bump jwks-rsa from 3.1.0 to 3.2.0 (#9684) 2025-03-29 19:11:53 +01:00
Parse Platform 51e2e537d2 refactor: Upgrade @graphql-tools/utils from 10.6.3 to 10.8.4 (#9676) 2025-03-28 01:54:21 +01:00
semantic-release-bot 59ad99a40e chore(release): 8.1.0-alpha.3 [skip ci]
# [8.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/8.1.0-alpha.2...8.1.0-alpha.3) (2025-03-27)

### Bug Fixes

* Parse Server doesn't shutdown gracefully ([#9634](https://github.com/parse-community/parse-server/issues/9634)) ([aed918d](https://github.com/parse-community/parse-server/commit/aed918d3109e739f7231d481b5f48c68fc01cf04))
2025-03-27 20:39:39 +00:00
Diamond Lewis aed918d310 fix: Parse Server doesn't shutdown gracefully (#9634) 2025-03-27 21:38:51 +01:00
semantic-release-bot f55de2b342 chore(release): 8.1.0-alpha.2 [skip ci]
# [8.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.1.0-alpha.1...8.1.0-alpha.2) (2025-03-27)

### Features

* Add Cloud Code triggers `Parse.Cloud.beforeFind(Parse.File)`and `Parse.Cloud.afterFind(Parse.File)` ([#8700](https://github.com/parse-community/parse-server/issues/8700)) ([b2beaa8](https://github.com/parse-community/parse-server/commit/b2beaa86ff543a7aa4ad274c7a23bc4aa302c3fa))
2025-03-27 17:23:09 +00:00
Daniel b2beaa86ff feat: Add Cloud Code triggers Parse.Cloud.beforeFind(Parse.File)and Parse.Cloud.afterFind(Parse.File) (#8700) 2025-03-27 18:22:14 +01:00
dependabot[bot] 042a92048a refactor: Bump eslint from 9.20.0 to 9.23.0 (#9681) 2025-03-27 16:29:58 +01:00
dependabot[bot] 4683820250 refactor: Bump router from 2.1.0 to 2.2.0 (#9682) 2025-03-27 15:48:59 +01:00
dependabot[bot] 06ebd02e68 refactor: Bump lint-staged from 15.4.3 to 15.5.0 (#9678) 2025-03-26 22:22:00 +01:00
dependabot[bot] a95e9af5b3 refactor: Bump @babel/preset-typescript from 7.26.0 to 7.27.0 (#9680) 2025-03-26 19:42:42 +01:00
dependabot[bot] dcbbda8d04 refactor: Bump @babel/cli from 7.26.4 to 7.27.0 (#9679) 2025-03-25 22:19:27 +01:00
dependabot[bot] 67f4c1aba5 refactor: Bump typescript from 5.7.3 to 5.8.2 (#9674) 2025-03-24 18:26:33 +01:00
dependabot[bot] b6d155f113 refactor: Bump commander from 13.0.0 to 13.1.0 (#9673) 2025-03-24 17:06:51 +01:00
semantic-release-bot bb74f02231 chore(release): 8.1.0-alpha.1 [skip ci]
# [8.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.0.2...8.1.0-alpha.1) (2025-03-24)

### Features

* Add default ACL ([#8701](https://github.com/parse-community/parse-server/issues/8701)) ([12b5d78](https://github.com/parse-community/parse-server/commit/12b5d781dc3f8c43c0c566dffa9308d02a7d8043))
2025-03-24 14:16:19 +00:00
Daniel 12b5d781dc feat: Add default ACL (#8701) 2025-03-24 15:15:27 +01:00
dependabot[bot] b9917dd734 refactor: Bump globals from 15.15.0 to 16.0.0 (#9670) 2025-03-21 14:19:10 +01:00
dependabot[bot] bde989916e refactor: Bump mongodb from 6.13.0 to 6.15.0 (#9659) 2025-03-21 13:37:06 +01:00
dependabot[bot] 3270089a51 refactor: Bump uuid from 11.0.5 to 11.1.0 (#9660) 2025-03-21 12:00:13 +01:00
semantic-release-bot f20e0f3ccd chore(release): 8.0.2 [skip ci]
## [8.0.2](https://github.com/parse-community/parse-server/compare/8.0.1...8.0.2) (2025-03-21)

### Bug Fixes

* Authentication provider credentials are usable across Parse Server apps; fixes security vulnerability [GHSA-837q-jhwx-cmpv](https://github.com/parse-community/parse-server/security/advisories/GHSA-837q-jhwx-cmpv) ([#9667](https://github.com/parse-community/parse-server/issues/9667)) ([5ef0440](https://github.com/parse-community/parse-server/commit/5ef0440c8e763854e62341acaeb6dc4ade3ba82f))
2025-03-21 10:15:55 +00:00
Manuel 4a79ffaa90 build: Release (#9669) 2025-03-21 11:14:56 +01:00
GitHub Actions 552a7713aa empty commit to trigger CI 2025-03-21 09:54:52 +00:00
semantic-release-bot 397842e657 chore(release): 8.0.2-alpha.1 [skip ci]
## [8.0.2-alpha.1](https://github.com/parse-community/parse-server/compare/8.0.1...8.0.2-alpha.1) (2025-03-21)

### Bug Fixes

* Authentication provider credentials are usable across Parse Server apps; fixes security vulnerability [GHSA-837q-jhwx-cmpv](https://github.com/parse-community/parse-server/security/advisories/GHSA-837q-jhwx-cmpv) ([#9667](https://github.com/parse-community/parse-server/issues/9667)) ([5ef0440](https://github.com/parse-community/parse-server/commit/5ef0440c8e763854e62341acaeb6dc4ade3ba82f))
2025-03-21 09:50:02 +00:00
Manuel 5ef0440c8e fix: Authentication provider credentials are usable across Parse Server apps; fixes security vulnerability [GHSA-837q-jhwx-cmpv](https://github.com/parse-community/parse-server/security/advisories/GHSA-837q-jhwx-cmpv) (#9667) 2025-03-21 10:49:09 +01:00
Manuel c56b2c49b2 docs: Add build step warning to contributing guide (#9666) 2025-03-21 09:35:22 +01:00
Corey 73380fba67 refactor: Bump pg-promise from 11.10.2 to 11.13.0 (#9661) 2025-03-19 20:28:15 +01:00
dependabot[bot] c0454e05ca refactor: Bump @graphql-tools/schema from 10.0.21 to 10.0.23 (#9657) 2025-03-19 02:43:15 +01:00
dependabot[bot] cc5b66375c refactor: Bump @babel/eslint-parser from 7.26.8 to 7.26.10 (#9658) 2025-03-18 20:39:34 +01:00
dependabot[bot] 31f1a3abcf refactor: Bump @parse/push-adapter from 6.10.0 to 6.11.0 (#9656) 2025-03-17 20:16:48 +01:00
dependabot[bot] 5a83b68b5f refactor: Bump form-data from 4.0.1 to 4.0.2 (#9655) 2025-03-17 19:55:24 +01:00
semantic-release-bot 81e9a93931 chore(release): 8.0.1 [skip ci]
## [8.0.1](https://github.com/parse-community/parse-server/compare/8.0.0...8.0.1) (2025-03-17)

### Bug Fixes

* Security upgrade node from 20.18.2-alpine3.20 to 20.19.0-alpine3.20 ([#9652](https://github.com/parse-community/parse-server/issues/9652)) ([2be1a19](https://github.com/parse-community/parse-server/commit/2be1a19a13d6f0f8e3eb4e399a6279ff4d01db76))
* Using Parse Server option `extendSessionOnUse` does not correctly clear memory and functions as a debounce instead of a throttle ([#8683](https://github.com/parse-community/parse-server/issues/8683)) ([6258a6a](https://github.com/parse-community/parse-server/commit/6258a6a11235dc642c71074d24e19c055294d26d))
2025-03-17 01:50:30 +00:00
Manuel 82214d130f build: Release (#9654) 2025-03-17 02:49:39 +01:00
GitHub Actions 4edea3bd72 empty commit to trigger CI 2025-03-17 01:35:35 +00:00
Manuel ac9e085a08 ci: Add auto-pr (#9653) 2025-03-17 02:34:02 +01:00
dependabot[bot] 1b20f49792 refactor: Bump @graphql-tools/merge from 9.0.22 to 9.0.24 (#9647) 2025-03-16 19:42:16 +01:00
semantic-release-bot 48217953e3 chore(release): 8.0.1-alpha.2 [skip ci]
## [8.0.1-alpha.2](https://github.com/parse-community/parse-server/compare/8.0.1-alpha.1...8.0.1-alpha.2) (2025-03-16)

### Bug Fixes

* Security upgrade node from 20.18.2-alpine3.20 to 20.19.0-alpine3.20 ([#9652](https://github.com/parse-community/parse-server/issues/9652)) ([2be1a19](https://github.com/parse-community/parse-server/commit/2be1a19a13d6f0f8e3eb4e399a6279ff4d01db76))
2025-03-16 18:12:45 +00:00
Parse Platform 2be1a19a13 fix: Security upgrade node from 20.18.2-alpine3.20 to 20.19.0-alpine3.20 (#9652) 2025-03-16 19:11:56 +01:00
dependabot[bot] b0388d52c0 refactor: Bump router from 2.0.0 to 2.1.0 (#9648) 2025-03-15 14:19:56 +01:00
dependabot[bot] de9462ae7d refactor: Bump @apollo/client from 3.12.8 to 3.13.4 (#9644) 2025-03-14 11:18:30 +01:00
dependabot[bot] 7b39e20bf9 refactor: Bump mongodb-runner from 5.7.1 to 5.8.0 (#9645) 2025-03-14 01:46:23 +01:00
dependabot[bot] 99bcfe2cde refactor: Bump @babel/helpers from 7.26.7 to 7.26.10 (#9635) 2025-03-13 00:20:25 +01:00
dependabot[bot] 858d9d290b refactor: Bump @graphql-tools/merge from 9.0.19 to 9.0.22 (#9642) 2025-03-12 23:35:18 +01:00
Diamond Lewis 97d4a9e783 refactor: Bump to jasmine 5.6.0 (#9453) 2025-03-11 21:34:14 +01:00
dependabot[bot] 5a2f3b8aec refactor: Bump ws from 8.18.0 to 8.18.1 (#9630) 2025-03-11 21:11:25 +01:00
Parse Platform 956d69cc1d refactor: Upgrade @babel/eslint-parser from 7.26.5 to 7.26.8 (#9633) 2025-03-11 20:35:53 +01:00
dependabot[bot] 4f55c3e9cf refactor: Bump @graphql-tools/schema from 10.0.16 to 10.0.21 (#9629) 2025-03-07 18:25:08 +01:00
Parse Platform bba2fe61b8 refactor: Upgrade graphql from 16.9.0 to 16.10.0 (#9514) 2025-03-06 14:42:39 +01:00
Daniel 533a60e218 refactor: Add internal method Utils.encodeForUrl for properly encoding email addresses for use in URLs (#9541) 2025-03-06 01:57:37 +01:00
semantic-release-bot 22e8568936 chore(release): 8.0.1-alpha.1 [skip ci]
## [8.0.1-alpha.1](https://github.com/parse-community/parse-server/compare/8.0.0...8.0.1-alpha.1) (2025-03-06)

### Bug Fixes

* Using Parse Server option `extendSessionOnUse` does not correctly clear memory and functions as a debounce instead of a throttle ([#8683](https://github.com/parse-community/parse-server/issues/8683)) ([6258a6a](https://github.com/parse-community/parse-server/commit/6258a6a11235dc642c71074d24e19c055294d26d))
2025-03-06 00:35:37 +00:00
Daniel 6258a6a112 fix: Using Parse Server option extendSessionOnUse does not correctly clear memory and functions as a debounce instead of a throttle (#8683) 2025-03-06 01:34:52 +01:00
semantic-release-bot 3cb3c5f7c6 chore(release): 8.0.0 [skip ci]
# [8.0.0](https://github.com/parse-community/parse-server/compare/7.4.0...8.0.0) (2025-03-04)

### Bug Fixes

* LiveQueryServer crashes using cacheAdapter on disconnect from Redis 4 server ([#9616](https://github.com/parse-community/parse-server/issues/9616)) ([bbc6bd4](https://github.com/parse-community/parse-server/commit/bbc6bd4b3f493170c13ad3314924cbf1f379eca4))
* Push adapter not loading on some versions of Node 22 ([#9524](https://github.com/parse-community/parse-server/issues/9524)) ([ff7f671](https://github.com/parse-community/parse-server/commit/ff7f671c79f5dcdc44e4319a10f3654e12662c23))
* Remove username from email verification and password reset process ([#8488](https://github.com/parse-community/parse-server/issues/8488)) ([d21dd97](https://github.com/parse-community/parse-server/commit/d21dd973363f9c5eca86a1007cb67e445b0d2e02))
* Security upgrade node from 20.17.0-alpine3.20 to 20.18.2-alpine3.20 ([#9583](https://github.com/parse-community/parse-server/issues/9583)) ([8f85ae2](https://github.com/parse-community/parse-server/commit/8f85ae205474f65414c0536754de12c87dbbf82a))

### Features

* Add dynamic master key by setting Parse Server option `masterKey` to a function ([#9582](https://github.com/parse-community/parse-server/issues/9582)) ([6f1d161](https://github.com/parse-community/parse-server/commit/6f1d161a2f263a166981f9544cf2aadce65afe23))
* Add support for MongoDB `databaseOptions` keys `autoSelectFamily`, `autoSelectFamilyAttemptTimeout` ([#9579](https://github.com/parse-community/parse-server/issues/9579)) ([5966068](https://github.com/parse-community/parse-server/commit/5966068e963e7a79eac8fba8720ee7d83578f207))
* Add support for MongoDB `databaseOptions` keys `minPoolSize`, `connectTimeoutMS`, `socketTimeoutMS` ([#9522](https://github.com/parse-community/parse-server/issues/9522)) ([91618fe](https://github.com/parse-community/parse-server/commit/91618fe738217b937cbfcec35969679e0adb7676))
* Add TypeScript support ([#9550](https://github.com/parse-community/parse-server/issues/9550)) ([59e46d0](https://github.com/parse-community/parse-server/commit/59e46d0aea3e6529994d98160d993144b8075291))
* Change default value of Parse Server option `encodeParseObjectInCloudFunction` to `true` ([#9527](https://github.com/parse-community/parse-server/issues/9527)) ([5c5ad69](https://github.com/parse-community/parse-server/commit/5c5ad69b4a917b7ed7c328a8255144e105c40b08))
* Deprecate `PublicAPIRouter` in favor of `PagesRouter` ([#9526](https://github.com/parse-community/parse-server/issues/9526)) ([7f66629](https://github.com/parse-community/parse-server/commit/7f666292e8b9692966672486b7108edefc356309))
* Increase required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` ([#9531](https://github.com/parse-community/parse-server/issues/9531)) ([871e508](https://github.com/parse-community/parse-server/commit/871e5082a9fd768cee3012e26d3c8ddff5c2952c))
* Increase required minimum Node versions to `18.20.4`, `20.18.0`, `22.12.0` ([#9521](https://github.com/parse-community/parse-server/issues/9521)) ([4e151cd](https://github.com/parse-community/parse-server/commit/4e151cd0a52191809452f197b2f29c3a12525b67))
* Increase required minimum versions to Postgres `15`, PostGIS `3.3` ([#9538](https://github.com/parse-community/parse-server/issues/9538)) ([89c9b54](https://github.com/parse-community/parse-server/commit/89c9b5485a07a411fb35de4f8cf0467e7eb01f85))
* Upgrade to express 5.0.1 ([#9530](https://github.com/parse-community/parse-server/issues/9530)) ([e0480df](https://github.com/parse-community/parse-server/commit/e0480dfa8d97946e57eac6b74d937978f8454b3a))
* Upgrade to Parse JS SDK 6.0.0 ([#9624](https://github.com/parse-community/parse-server/issues/9624)) ([bf9db75](https://github.com/parse-community/parse-server/commit/bf9db75e8685def1407034944725e758bc926c26))

### BREAKING CHANGES

* This upgrades the internally used Express framework from version 4 to 5, which may be a breaking change. If Parse Server is set up to be mounted on an Express application, we recommend to also use version 5 of the Express framework to avoid any compatibility issues. Note that even if there are no issues after upgrading, future releases of Parse Server may introduce issues if Parse Server internally relies on Express 5-specific features which are unsupported by the Express version on which it is mounted. See the Express [migration guide](https://expressjs.com/en/guide/migrating-5.html) and [release announcement](https://expressjs.com/2024/10/15/v5-release.html#breaking-changes) for more info. ([e0480df](e0480df))
* This upgrades to the Parse JS SDK 6.0.0. See the [change log](https://github.com/parse-community/Parse-SDK-JS/releases/tag/6.0.0) of the Parse JS SDK for breaking changes and more details. ([bf9db75](bf9db75))
* This removes the username from the email verification and password reset process to prevent storing personally identifiable information (PII) in server and infrastructure logs. Customized HTML pages or emails related to email verification and password reset may need to be adapted accordingly. See the new templates that come bundled with Parse Server and the [migration guide](https://github.com/parse-community/parse-server/blob/alpha/8.0.0.md) for more details. ([d21dd97](d21dd97))
* This releases increases the required minimum versions to Postgres `15`, PostGIS `3.3` and removes support for Postgres `13`, `14`, PostGIS `3.1`, `3.2`. ([89c9b54](89c9b54))
* The default value of Parse Server option `encodeParseObjectInCloudFunction` changes to `true`; the option has been deprecated and will be removed in a future version. ([5c5ad69](5c5ad69))
* This releases increases the required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` and removes support for MongoDB `4`, `5`. ([871e508](871e508))
* This releases increases the required minimum Node versions to 18.20.4, 20.18.0, 22.12.0 and removes unofficial support for Node 19. ([4e151cd](4e151cd))
2025-03-04 01:45:14 +00:00
Manuel 7e88cb5cea build: Release (#9628) 2025-03-04 02:44:27 +01:00
Manuel Trezza 34867b7e30 Merge branch 'release' into build/release 2025-03-04 02:13:45 +01:00
Manuel d4eab0e628 ci: Remove beta branch (#9626) 2025-03-04 02:10:52 +01:00
semantic-release-bot 9c2d9932de chore(release): 8.0.0-alpha.15 [skip ci]
# [8.0.0-alpha.15](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.14...8.0.0-alpha.15) (2025-03-03)

### Features

* Upgrade to express 5.0.1 ([#9530](https://github.com/parse-community/parse-server/issues/9530)) ([e0480df](https://github.com/parse-community/parse-server/commit/e0480dfa8d97946e57eac6b74d937978f8454b3a))

### BREAKING CHANGES

* This upgrades the internally used Express framework from version 4 to 5, which may be a breaking change. If Parse Server is set up to be mounted on an Express application, we recommend to also use version 5 of the Express framework to avoid any compatibility issues. Note that even if there are no issues after upgrading, future releases of Parse Server may introduce issues if Parse Server internally relies on Express 5-specific features which are unsupported by the Express version on which it is mounted. See the Express [migration guide](https://expressjs.com/en/guide/migrating-5.html) and [release announcement](https://expressjs.com/2024/10/15/v5-release.html#breaking-changes) for more info. ([e0480df](e0480df))
2025-03-03 21:12:36 +00:00
Colin Ulin e0480dfa8d feat: Upgrade to express 5.0.1 (#9530)
BREAKING CHANGE: This upgrades the internally used Express framework from version 4 to 5, which may be a breaking change. If Parse Server is set up to be mounted on an Express application, we recommend to also use version 5 of the Express framework to avoid any compatibility issues. Note that even if there are no issues after upgrading, future releases of Parse Server may introduce issues if Parse Server internally relies on Express 5-specific features which are unsupported by the Express version on which it is mounted. See the Express [migration guide](https://expressjs.com/en/guide/migrating-5.html) and [release announcement](https://expressjs.com/2024/10/15/v5-release.html#breaking-changes) for more info.
2025-03-03 22:11:42 +01:00
semantic-release-bot cc8dad8fa1 chore(release): 8.0.0-alpha.14 [skip ci]
# [8.0.0-alpha.14](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.13...8.0.0-alpha.14) (2025-03-02)

### Features

* Upgrade to Parse JS SDK 6.0.0 ([#9624](https://github.com/parse-community/parse-server/issues/9624)) ([bf9db75](https://github.com/parse-community/parse-server/commit/bf9db75e8685def1407034944725e758bc926c26))

### BREAKING CHANGES

* This upgrades to the Parse JS SDK 6.0.0. See the [change log](https://github.com/parse-community/Parse-SDK-JS/releases/tag/6.0.0) of the Parse JS SDK for breaking changes and more details. ([bf9db75](bf9db75))
2025-03-02 23:48:30 +00:00
Daniel bf9db75e86 feat: Upgrade to Parse JS SDK 6.0.0 (#9624)
BREAKING CHANGE: This upgrades to the Parse JS SDK 6.0.0. See the [change log](https://github.com/parse-community/Parse-SDK-JS/releases/tag/6.0.0) of the Parse JS SDK for breaking changes and more details.
2025-03-03 00:47:40 +01:00
semantic-release-bot 275fe3782b chore(release): 8.0.0-alpha.13 [skip ci]
# [8.0.0-alpha.13](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.12...8.0.0-alpha.13) (2025-03-02)

### Bug Fixes

* Remove username from email verification and password reset process ([#8488](https://github.com/parse-community/parse-server/issues/8488)) ([d21dd97](https://github.com/parse-community/parse-server/commit/d21dd973363f9c5eca86a1007cb67e445b0d2e02))

### BREAKING CHANGES

* This removes the username from the email verification and password reset process to prevent storing personally identifiable information (PII) in server and infrastructure logs. Customized HTML pages or emails related to email verification and password reset may need to be adapted accordingly. See the new templates that come bundled with Parse Server and the [migration guide](https://github.com/parse-community/parse-server/blob/alpha/8.0.0.md) for more details. ([d21dd97](d21dd97))
2025-03-02 01:33:32 +00:00
Daniel d21dd97336 fix: Remove username from email verification and password reset process (#8488)
BREAKING CHANGE: This removes the username from the email verification and password reset process to prevent storing personally identifiable information (PII) in server and infrastructure logs. Customized HTML pages or emails related to email verification and password reset may need to be adapted accordingly. See the new templates that come bundled with Parse Server and the [migration guide](https://github.com/parse-community/parse-server/blob/alpha/8.0.0.md) for more details.
2025-03-02 02:32:43 +01:00
semantic-release-bot 6a6bc2a8cc chore(release): 8.0.0-alpha.12 [skip ci]
# [8.0.0-alpha.12](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.11...8.0.0-alpha.12) (2025-02-24)

### Bug Fixes

* LiveQueryServer crashes using cacheAdapter on disconnect from Redis 4 server ([#9616](https://github.com/parse-community/parse-server/issues/9616)) ([bbc6bd4](https://github.com/parse-community/parse-server/commit/bbc6bd4b3f493170c13ad3314924cbf1f379eca4))
2025-02-24 01:49:00 +00:00
Mohammad Ali bbc6bd4b3f fix: LiveQueryServer crashes using cacheAdapter on disconnect from Redis 4 server (#9616) 2025-02-24 02:48:10 +01:00
dependabot[bot] ef68fb1057 refactor: Bump @babel/core from 7.26.7 to 7.26.8 (#9612) 2025-02-14 15:00:59 +01:00
dependabot[bot] 455c2b3aeb refactor: Bump globals from 15.14.0 to 15.15.0 (#9611) 2025-02-13 18:03:30 +01:00
dependabot[bot] 0a5a0ae9cd refactor: Bump @graphql-tools/merge from 9.0.18 to 9.0.19 (#9603) 2025-02-12 22:48:21 +01:00
semantic-release-bot d89d8a4815 chore(release): 8.0.0-alpha.11 [skip ci]
# [8.0.0-alpha.11](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.10...8.0.0-alpha.11) (2025-02-12)

### Features

* Add dynamic master key by setting Parse Server option `masterKey` to a function ([#9582](https://github.com/parse-community/parse-server/issues/9582)) ([6f1d161](https://github.com/parse-community/parse-server/commit/6f1d161a2f263a166981f9544cf2aadce65afe23))
2025-02-12 21:24:08 +00:00
Daniel 6f1d161a2f feat: Add dynamic master key by setting Parse Server option masterKey to a function (#9582) 2025-02-12 22:23:18 +01:00
dependabot[bot] 415373708a refactor: Bump eslint from 9.19.0 to 9.20.0 (#9601) 2025-02-11 05:45:53 +01:00
dependabot[bot] 27bc74ab1f refactor: Bump @graphql-tools/merge from 9.0.17 to 9.0.18 (#9602) 2025-02-10 22:45:04 +01:00
Daniel d0b2db68f6 ci: Remove dtslint (#9599) 2025-02-09 13:27:53 +01:00
dependabot[bot] be7d6e8982 refactor: Bump semver from 7.6.3 to 7.7.1 (#9598) 2025-02-07 15:42:36 +01:00
dependabot[bot] 80c7181586 refactor: Bump @parse/push-adapter from 6.9.1 to 6.10.0 (#9596) 2025-02-06 12:59:58 +01:00
dependabot[bot] 9f1232e669 refactor: Bump mongodb from 6.12.0 to 6.13.0 (#9594) 2025-02-05 19:33:33 +01:00
Parse Platform 01334173e6 refactor: Upgrade @parse/push-adapter from 6.8.0 to 6.9.1 (#9586) 2025-02-04 22:49:53 +01:00
dependabot[bot] 3f4a34efc6 refactor: Bump express-rate-limit from 7.4.1 to 7.5.0 (#9587) 2025-02-04 12:20:02 +01:00
dependabot[bot] d09762c703 refactor: Bump @babel/eslint-parser from 7.25.9 to 7.26.5 (#9585) 2025-02-03 17:24:45 +01:00
semantic-release-bot d4d805c21c chore(release): 8.0.0-alpha.10 [skip ci]
# [8.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.9...8.0.0-alpha.10) (2025-02-01)

### Bug Fixes

* Security upgrade node from 20.17.0-alpine3.20 to 20.18.2-alpine3.20 ([#9583](https://github.com/parse-community/parse-server/issues/9583)) ([8f85ae2](https://github.com/parse-community/parse-server/commit/8f85ae205474f65414c0536754de12c87dbbf82a))
2025-02-01 19:11:39 +00:00
Parse Platform 8f85ae2054 fix: Security upgrade node from 20.17.0-alpine3.20 to 20.18.2-alpine3.20 (#9583) 2025-02-01 20:10:44 +01:00
Daniel 889dbb5aee refactor: Upgrade to eslint 9.19.0 (#9580) 2025-02-01 15:32:43 +01:00
semantic-release-bot 239e692145 chore(release): 8.0.0-alpha.9 [skip ci]
# [8.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.8...8.0.0-alpha.9) (2025-01-30)

### Features

* Add TypeScript support ([#9550](https://github.com/parse-community/parse-server/issues/9550)) ([59e46d0](https://github.com/parse-community/parse-server/commit/59e46d0aea3e6529994d98160d993144b8075291))
2025-01-30 00:46:25 +00:00
Daniel 59e46d0aea feat: Add TypeScript support (#9550) 2025-01-30 01:45:35 +01:00
semantic-release-bot a97d41864e chore(release): 8.0.0-alpha.8 [skip ci]
# [8.0.0-alpha.8](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.7...8.0.0-alpha.8) (2025-01-30)

### Features

* Add support for MongoDB `databaseOptions` keys `autoSelectFamily`, `autoSelectFamilyAttemptTimeout` ([#9579](https://github.com/parse-community/parse-server/issues/9579)) ([5966068](https://github.com/parse-community/parse-server/commit/5966068e963e7a79eac8fba8720ee7d83578f207))
2025-01-30 00:28:58 +00:00
Colin Ulin 5966068e96 feat: Add support for MongoDB databaseOptions keys autoSelectFamily, autoSelectFamilyAttemptTimeout (#9579) 2025-01-30 01:28:04 +01:00
dependabot[bot] d1f6d3aee2 refactor: Bump lint-staged from 15.4.1 to 15.4.3 (#9576) 2025-01-29 21:34:27 +01:00
Daniel a68f71b3de refactor: Upgrade to commander 13.0.0 (#9574) 2025-01-29 06:04:54 +01:00
dependabot[bot] ea5ee682a7 refactor: Bump @apollo/client from 3.12.7 to 3.12.8 (#9575) 2025-01-28 13:37:21 +01:00
semantic-release-bot e6bf0041f4 chore(release): 8.0.0-alpha.7 [skip ci]
# [8.0.0-alpha.7](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.6...8.0.0-alpha.7) (2025-01-28)

### Features

* Add support for MongoDB `databaseOptions` keys `minPoolSize`, `connectTimeoutMS`, `socketTimeoutMS` ([#9522](https://github.com/parse-community/parse-server/issues/9522)) ([91618fe](https://github.com/parse-community/parse-server/commit/91618fe738217b937cbfcec35969679e0adb7676))
2025-01-28 01:22:31 +00:00
Colin Ulin 91618fe738 feat: Add support for MongoDB databaseOptions keys minPoolSize, connectTimeoutMS, socketTimeoutMS (#9522) 2025-01-28 02:21:40 +01:00
dependabot[bot] 3b20a6f039 refactor: Bump @babel/core from 7.26.0 to 7.26.7 (#9572) 2025-01-27 15:01:10 +01:00
dependabot[bot] 5ca0aa3cd3 refactor: Bump @apollo/client from 3.12.6 to 3.12.7 (#9569) 2025-01-24 23:45:08 +01:00
dependabot[bot] 6181652cce refactor: Bump uuid from 11.0.3 to 11.0.5 (#9568) 2025-01-24 00:47:39 +01:00
dependabot[bot] 42f785e465 refactor: Bump lint-staged from 15.3.0 to 15.4.1 (#9563) 2025-01-21 14:38:12 +01:00
dependabot[bot] 0a2302338d refactor: Bump @babel/plugin-transform-flow-strip-types from 7.25.9 to 7.26.5 (#9562) 2025-01-20 20:36:21 +01:00
dependabot[bot] 0644f42914 refactor: Bump @apollo/client from 3.12.3 to 3.12.6 (#9561) 2025-01-20 16:08:23 +01:00
dependabot[bot] 1b8ecba632 refactor: Bump yaml from 2.6.1 to 2.7.0 (#9559) 2025-01-17 19:21:12 +01:00
Daniel 34636be5b7 test: Add test for saving file without extension (#9535) 2025-01-16 15:33:12 +01:00
dependabot[bot] 7194cccd56 refactor: Bump @graphql-tools/merge from 9.0.14 to 9.0.17 (#9552) 2025-01-16 14:01:02 +01:00
dependabot[bot] 59340ce399 refactor: Bump lint-staged from 15.2.11 to 15.3.0 (#9548) 2025-01-16 03:39:32 +01:00
dependabot[bot] cdf5115ef6 refactor: Bump @apollo/server from 4.11.2 to 4.11.3 (#9549) 2025-01-16 02:42:46 +01:00
dependabot[bot] 970528ddff refactor: Bump @semantic-release/commit-analyzer from 13.0.0 to 13.0.1 (#9543) 2025-01-14 22:39:11 +01:00
dependabot[bot] ad0a7bc0ba refactor: Bump @graphql-tools/schema from 10.0.13 to 10.0.16 (#9542) 2025-01-14 19:51:58 +01:00
dependabot[bot] 28b3edee4e refactor: Bump semantic-release from 24.2.0 to 24.2.1 (#9539) 2025-01-13 16:19:51 +01:00
dependabot[bot] 1b61cab81c refactor: Bump @semantic-release/release-notes-generator from 14.0.1 to 14.0.3 (#9540) 2025-01-13 15:47:17 +01:00
dependabot[bot] a0efad88d2 refactor: Bump otpauth from 9.3.5 to 9.3.6 (#9493) 2025-01-12 21:55:48 +01:00
dependabot[bot] bb1daafef0 refactor: Bump mime from 4.0.4 to 4.0.6 (#9502) 2025-01-12 19:53:43 +01:00
semantic-release-bot 3f0f29b4df chore(release): 8.0.0-alpha.6 [skip ci]
# [8.0.0-alpha.6](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.5...8.0.0-alpha.6) (2025-01-12)

### Features

* Increase required minimum versions to Postgres `15`, PostGIS `3.3` ([#9538](https://github.com/parse-community/parse-server/issues/9538)) ([89c9b54](https://github.com/parse-community/parse-server/commit/89c9b5485a07a411fb35de4f8cf0467e7eb01f85))

### BREAKING CHANGES

* This releases increases the required minimum versions to Postgres `15`, PostGIS `3.3` and removes support for Postgres `13`, `14`, PostGIS `3.1`, `3.2`. ([89c9b54](89c9b54))
2025-01-12 14:04:34 +00:00
Manuel 89c9b5485a feat: Increase required minimum versions to Postgres 15, PostGIS 3.3 (#9538)
BREAKING CHANGE: This releases increases the required minimum versions to Postgres `15`, PostGIS `3.3` and removes support for Postgres `13`, `14`, PostGIS `3.1`, `3.2`.
2025-01-12 15:03:37 +01:00
semantic-release-bot 6895768fe3 chore(release): 8.0.0-alpha.5 [skip ci]
# [8.0.0-alpha.5](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.4...8.0.0-alpha.5) (2025-01-12)

### Features

* Change default value of Parse Server option `encodeParseObjectInCloudFunction` to `true` ([#9527](https://github.com/parse-community/parse-server/issues/9527)) ([5c5ad69](https://github.com/parse-community/parse-server/commit/5c5ad69b4a917b7ed7c328a8255144e105c40b08))

### BREAKING CHANGES

* The default value of Parse Server option `encodeParseObjectInCloudFunction` changes to `true`; the option has been deprecated and will be removed in a future version. ([5c5ad69](5c5ad69))
2025-01-12 03:35:47 +00:00
Daniel 5c5ad69b4a feat: Change default value of Parse Server option encodeParseObjectInCloudFunction to true (#9527)
BREAKING CHANGE: The default value of Parse Server option `encodeParseObjectInCloudFunction` changes to `true`; the option has been deprecated and will be removed in a future version.
2025-01-12 04:34:52 +01:00
semantic-release-bot 7534eb705a chore(release): 8.0.0-alpha.4 [skip ci]
# [8.0.0-alpha.4](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.3...8.0.0-alpha.4) (2025-01-12)

### Features

* Deprecate `PublicAPIRouter` in favor of `PagesRouter` ([#9526](https://github.com/parse-community/parse-server/issues/9526)) ([7f66629](https://github.com/parse-community/parse-server/commit/7f666292e8b9692966672486b7108edefc356309))
2025-01-12 01:00:29 +00:00
Daniel 7f666292e8 feat: Deprecate PublicAPIRouter in favor of PagesRouter (#9526) 2025-01-12 01:59:40 +01:00
semantic-release-bot 85b71dac09 chore(release): 8.0.0-alpha.3 [skip ci]
# [8.0.0-alpha.3](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.2...8.0.0-alpha.3) (2025-01-12)

### Features

* Increase required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` ([#9531](https://github.com/parse-community/parse-server/issues/9531)) ([871e508](https://github.com/parse-community/parse-server/commit/871e5082a9fd768cee3012e26d3c8ddff5c2952c))

### BREAKING CHANGES

* This releases increases the required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` and removes support for MongoDB `4`, `5`. ([871e508](871e508))
2025-01-12 00:45:02 +00:00
Manuel 871e5082a9 feat: Increase required minimum MongoDB versions to 6.0.19, 7.0.16, 8.0.4 (#9531)
BREAKING CHANGE: This releases increases the required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` and removes support for MongoDB `4`, `5`.
2025-01-12 01:44:10 +01:00
semantic-release-bot fbf78f0802 chore(release): 8.0.0-alpha.2 [skip ci]
# [8.0.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.0.0-alpha.1...8.0.0-alpha.2) (2025-01-11)

### Bug Fixes

* Push adapter not loading on some versions of Node 22 ([#9524](https://github.com/parse-community/parse-server/issues/9524)) ([ff7f671](https://github.com/parse-community/parse-server/commit/ff7f671c79f5dcdc44e4319a10f3654e12662c23))
2025-01-11 18:02:17 +00:00
Daniel ff7f671c79 fix: Push adapter not loading on some versions of Node 22 (#9524) 2025-01-11 19:01:28 +01:00
semantic-release-bot 93b2bb7d77 chore(release): 8.0.0-alpha.1 [skip ci]
# [8.0.0-alpha.1](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.7...8.0.0-alpha.1) (2025-01-11)

### Features

* Increase required minimum Node versions to `18.20.4`, `20.18.0`, `22.12.0` ([#9521](https://github.com/parse-community/parse-server/issues/9521)) ([4e151cd](https://github.com/parse-community/parse-server/commit/4e151cd0a52191809452f197b2f29c3a12525b67))

### BREAKING CHANGES

* This releases increases the required minimum Node versions to 18.20.4, 20.18.0, 22.12.0 and removes unofficial support for Node 19. ([4e151cd](4e151cd))
2025-01-11 17:43:23 +00:00
Manuel 4e151cd0a5 feat: Increase required minimum Node versions to 18.20.4, 20.18.0, 22.12.0 (#9521)
BREAKING CHANGE: This releases increases the required minimum Node versions to 18.20.4, 20.18.0, 22.12.0 and removes unofficial support for Node 19.
2025-01-11 18:42:22 +01:00
semantic-release-bot 2cebb88989 chore(release): 7.4.0 [skip ci]
# [7.4.0](https://github.com/parse-community/parse-server/compare/7.3.0...7.4.0) (2024-12-23)

### Bug Fixes

* `Parse.Query.distinct` fails due to invalid aggregate stage 'hint' ([#9295](https://github.com/parse-community/parse-server/issues/9295)) ([5f66c6a](https://github.com/parse-community/parse-server/commit/5f66c6a075cbe1cdaf9d1b108ee65af8ae596b89))
* Security upgrade cross-spawn from 7.0.3 to 7.0.6 ([#9444](https://github.com/parse-community/parse-server/issues/9444)) ([3d034e0](https://github.com/parse-community/parse-server/commit/3d034e0a993e3e5bd9bb96a7e382bb3464f1eb68))
* Security upgrade fast-xml-parser from 4.4.0 to 4.4.1 ([#9262](https://github.com/parse-community/parse-server/issues/9262)) ([992d39d](https://github.com/parse-community/parse-server/commit/992d39d508f230c774dcb764d1d907ec8887e6c5))
* Security upgrade node from 20.14.0-alpine3.20 to 20.17.0-alpine3.20 ([#9300](https://github.com/parse-community/parse-server/issues/9300)) ([15bb17d](https://github.com/parse-community/parse-server/commit/15bb17d87153bf0d38f08fe4c720da29a204b36b))

### Features

* Add support for MongoDB 8 ([#9269](https://github.com/parse-community/parse-server/issues/9269)) ([4756c66](https://github.com/parse-community/parse-server/commit/4756c66cd9f55afa1621d1a3f6fa850ed605cb53))
* Add support for PostGIS 3.5 ([#9354](https://github.com/parse-community/parse-server/issues/9354)) ([8ea3538](https://github.com/parse-community/parse-server/commit/8ea35382db3436d54ab59bd30706705564b0985c))
* Add support for Postgres 17 ([#9324](https://github.com/parse-community/parse-server/issues/9324)) ([fa2ee31](https://github.com/parse-community/parse-server/commit/fa2ee3196e4319a142b3838bb947c98dcba5d5cb))
* Upgrade @parse/push-adapter from 6.7.1 to 6.8.0 ([#9489](https://github.com/parse-community/parse-server/issues/9489)) ([286aa66](https://github.com/parse-community/parse-server/commit/286aa664ac8830d36c3e70d2316917d15f0b6df5))
2024-12-23 14:48:00 +00:00
Manuel ef59e2e310 build: Release (#9504) 2024-12-23 15:47:04 +01:00
Manuel Trezza f51b5ce32d empty 2024-12-23 15:15:29 +01:00
semantic-release-bot a579eebe79 chore(release): 7.4.0-beta.1 [skip ci]
# [7.4.0-beta.1](https://github.com/parse-community/parse-server/compare/7.3.0...7.4.0-beta.1) (2024-12-23)

### Bug Fixes

* `Parse.Query.distinct` fails due to invalid aggregate stage 'hint' ([#9295](https://github.com/parse-community/parse-server/issues/9295)) ([5f66c6a](https://github.com/parse-community/parse-server/commit/5f66c6a075cbe1cdaf9d1b108ee65af8ae596b89))
* Security upgrade cross-spawn from 7.0.3 to 7.0.6 ([#9444](https://github.com/parse-community/parse-server/issues/9444)) ([3d034e0](https://github.com/parse-community/parse-server/commit/3d034e0a993e3e5bd9bb96a7e382bb3464f1eb68))
* Security upgrade fast-xml-parser from 4.4.0 to 4.4.1 ([#9262](https://github.com/parse-community/parse-server/issues/9262)) ([992d39d](https://github.com/parse-community/parse-server/commit/992d39d508f230c774dcb764d1d907ec8887e6c5))
* Security upgrade node from 20.14.0-alpine3.20 to 20.17.0-alpine3.20 ([#9300](https://github.com/parse-community/parse-server/issues/9300)) ([15bb17d](https://github.com/parse-community/parse-server/commit/15bb17d87153bf0d38f08fe4c720da29a204b36b))

### Features

* Add support for MongoDB 8 ([#9269](https://github.com/parse-community/parse-server/issues/9269)) ([4756c66](https://github.com/parse-community/parse-server/commit/4756c66cd9f55afa1621d1a3f6fa850ed605cb53))
* Add support for PostGIS 3.5 ([#9354](https://github.com/parse-community/parse-server/issues/9354)) ([8ea3538](https://github.com/parse-community/parse-server/commit/8ea35382db3436d54ab59bd30706705564b0985c))
* Add support for Postgres 17 ([#9324](https://github.com/parse-community/parse-server/issues/9324)) ([fa2ee31](https://github.com/parse-community/parse-server/commit/fa2ee3196e4319a142b3838bb947c98dcba5d5cb))
* Upgrade @parse/push-adapter from 6.7.1 to 6.8.0 ([#9489](https://github.com/parse-community/parse-server/issues/9489)) ([286aa66](https://github.com/parse-community/parse-server/commit/286aa664ac8830d36c3e70d2316917d15f0b6df5))
2024-12-23 14:11:14 +00:00
Manuel c772f7bc47 build: Release (#9503) 2024-12-23 15:10:12 +01:00
Manuel Trezza 4f37f25d26 empty 2024-12-23 12:55:48 +01:00
semantic-release-bot 3b6ef038b1 chore(release): 7.4.0-alpha.7 [skip ci]
# [7.4.0-alpha.7](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.6...7.4.0-alpha.7) (2024-12-16)

### Features

* Upgrade @parse/push-adapter from 6.7.1 to 6.8.0 ([#9489](https://github.com/parse-community/parse-server/issues/9489)) ([286aa66](https://github.com/parse-community/parse-server/commit/286aa664ac8830d36c3e70d2316917d15f0b6df5))
2024-12-16 18:42:18 +00:00
dependabot[bot] 286aa664ac feat: Upgrade @parse/push-adapter from 6.7.1 to 6.8.0 (#9489) 2024-12-16 19:41:19 +01:00
dependabot[bot] 7bd76be7b2 refactor: Bump @graphql-tools/schema from 10.0.12 to 10.0.13 (#9490) 2024-12-16 15:33:33 +01:00
dependabot[bot] 5b079575ce refactor: Bump @graphql-tools/merge from 9.0.12 to 9.0.14 (#9488) 2024-12-16 14:05:29 +01:00
dependabot[bot] e1a3b51a07 refactor: Bump @graphql-tools/utils from 10.6.2 to 10.6.3 (#9484) 2024-12-13 19:22:23 +01:00
dependabot[bot] ce62a9b8de refactor: Bump @graphql-tools/schema from 10.0.11 to 10.0.12 (#9486) 2024-12-13 17:11:18 +01:00
dependabot[bot] b0aecda4ed refactor: Bump @apollo/client from 3.12.2 to 3.12.3 (#9485) 2024-12-13 16:39:22 +01:00
dependabot[bot] 05e2471409 refactor: Bump lint-staged from 15.2.10 to 15.2.11 (#9482) 2024-12-11 19:28:28 +01:00
dependabot[bot] 02cd5a39b4 refactor: Bump mongodb from 6.11.0 to 6.12.0 (#9481) 2024-12-11 17:27:35 +01:00
dependabot[bot] 7db9ca0249 refactor: Bump @graphql-tools/merge from 9.0.11 to 9.0.12 (#9476) 2024-12-10 22:57:31 +01:00
dependabot[bot] 2f56a57e4e refactor: Bump @node-rs/bcrypt from 1.10.5 to 1.10.7 (#9480)
ot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 22:15:49 +01:00
dependabot[bot] b6aaa1e09a refactor: Bump @babel/cli from 7.25.9 to 7.26.4 (#9475) 2024-12-10 20:39:22 +01:00
dependabot[bot] 9a660b98de refactor: Bump @graphql-tools/schema from 10.0.10 to 10.0.11 (#9477) 2024-12-10 11:44:18 +01:00
Manuel d097929e1c ci: Fix invalid MongoDB version ranges for tests (#9474) 2024-12-09 01:18:57 +01:00
Parse Platform 6146777151 refactor: Security upgrade express from 4.21.1 to 4.21.2 (#9473) 2024-12-08 12:57:51 +01:00
dependabot[bot] 30d1e007b6 refactor: Bump @graphql-tools/utils from 10.6.1 to 10.6.2 (#9471) 2024-12-08 11:04:32 +01:00
dependabot[bot] 0825f46650 refactor: Bump @apollo/client from 3.11.10 to 3.12.2 (#9472) 2024-12-08 01:43:14 +01:00
dependabot[bot] 0a8f569697 refactor: Bump @graphql-tools/schema from 10.0.9 to 10.0.10 (#9465) 2024-12-03 11:15:53 +01:00
dependabot[bot] f75bec9e75 refactor: Bump @graphql-tools/utils from 10.5.6 to 10.6.1 (#9461) 2024-11-30 17:56:44 +01:00
dependabot[bot] 7242a4f6a3 refactor: Bump @graphql-tools/merge from 9.0.9 to 9.0.11 (#9462) 2024-11-30 11:37:49 +01:00
dependabot[bot] d9c59cc6ab refactor: Bump mongodb from 6.10.0 to 6.11.0 (#9457) 2024-11-28 18:40:34 +01:00
dependabot[bot] e9ff8c7c5c refactor: Bump @graphql-tools/schema from 10.0.8 to 10.0.9 (#9455) 2024-11-23 20:57:50 +00:00
dependabot[bot] ef33ac3207 refactor: Bump husky from 9.1.6 to 9.1.7 (#9451) 2024-11-21 19:55:15 +01:00
dependabot[bot] 2ba374fe04 refactor: Bump @parse/push-adapter from 6.7.0 to 6.7.1 (#9452) 2024-11-21 17:59:48 +01:00
dependabot[bot] b20a1c745c refactor: Bump yaml from 2.6.0 to 2.6.1 (#9446) 2024-11-20 20:36:32 +01:00
dependabot[bot] 9710bca11b refactor: Bump otpauth from 9.3.4 to 9.3.5 (#9448) 2024-11-20 19:47:58 +01:00
dependabot[bot] b2d94eb2d2 refactor: Bump @apollo/client from 3.11.9 to 3.11.10 (#9430) 2024-11-20 01:58:27 +01:00
semantic-release-bot 8b2a71da58 chore(release): 7.4.0-alpha.6 [skip ci]
# [7.4.0-alpha.6](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.5...7.4.0-alpha.6) (2024-11-19)

### Bug Fixes

* Security upgrade cross-spawn from 7.0.3 to 7.0.6 ([#9444](https://github.com/parse-community/parse-server/issues/9444)) ([3d034e0](https://github.com/parse-community/parse-server/commit/3d034e0a993e3e5bd9bb96a7e382bb3464f1eb68))
2024-11-19 20:06:34 +00:00
dependabot[bot] 3d034e0a99 fix: Security upgrade cross-spawn from 7.0.3 to 7.0.6 (#9444) 2024-11-19 21:05:33 +01:00
dependabot[bot] 0bc0ab4bf9 refactor: Bump @graphql-tools/utils from 10.5.5 to 10.5.6 (#9433) 2024-11-19 14:37:03 +01:00
dependabot[bot] f448322186 refactor: Bump @graphql-tools/schema from 10.0.7 to 10.0.8 (#9435) 2024-11-19 14:06:34 +01:00
dependabot[bot] 71b832a7f4 refactor: Bump @graphql-tools/merge from 9.0.8 to 9.0.9 (#9434) 2024-11-14 13:50:45 +01:00
dependabot[bot] 91f9aca25b refactor: Bump uuid from 11.0.2 to 11.0.3 (#9427) 2024-11-12 12:03:36 +01:00
dependabot[bot] 17074c55bd refactor: Bump pg-promise from 11.10.1 to 11.10.2 (#9428) 2024-11-11 19:59:07 +01:00
dependabot[bot] f83d923702 refactor: Bump winston from 3.16.0 to 3.17.0 (#9429) 2024-11-11 14:19:32 +01:00
dependabot[bot] 2ab95e0335 refactor: Bump @apollo/client from 3.11.8 to 3.11.9 (#9415) 2024-11-08 18:52:07 +01:00
dependabot[bot] 606ae54a95 refactor: Bump @babel/cli from 7.24.8 to 7.25.9 (#9412) 2024-11-07 19:01:17 +01:00
dependabot[bot] 987210be71 refactor: Bump @semantic-release/github from 11.0.0 to 11.0.1 (#9413) 2024-11-07 16:50:02 +01:00
dependabot[bot] f511b0f673 refactor: Bump @apollo/server from 4.11.0 to 4.11.2 (#9409) 2024-11-07 02:05:13 +01:00
dependabot[bot] 5591af403b refactor: Bump lint-staged from 10.2.3 to 15.2.10 (#9411) 2024-11-06 13:34:02 +01:00
dependabot[bot] eba2e5f8bf refactor: Bump @semantic-release/github from 10.3.5 to 11.0.0 (#9406) 2024-11-05 23:35:14 +01:00
dependabot[bot] 6d9be91405 refactor: Bump @parse/push-adapter from 6.4.1 to 6.7.0 (#9408) 2024-11-05 20:11:54 +01:00
dependabot[bot] 011bb997c2 refactor: Bump mongodb-runner from 5.7.0 to 5.7.1 (#9407) 2024-11-05 18:56:06 +01:00
dependabot[bot] 02b09acf7f refactor: Bump semantic-release from 24.0.0 to 24.2.0 (#9403) 2024-11-04 18:49:00 +01:00
dependabot[bot] b73873b10f refactor: Bump winston from 3.15.0 to 3.16.0 (#9404) 2024-11-04 16:51:41 +01:00
dependabot[bot] 30a836dae7 refactor: Bump nyc from 15.1.0 to 17.1.0 (#9401) 2024-11-01 13:32:01 +01:00
dependabot[bot] c8bc74a80f refactor: Bump @node-rs/bcrypt from 1.10.4 to 1.10.5 (#9397) 2024-10-31 14:32:37 +01:00
dependabot[bot] de07faaafe refactor: Bump express from 4.21.0 to 4.21.1 (#9398) 2024-10-31 13:32:32 +01:00
Manuel 4665b59742 ci: Add permissions to workflows (#9395) 2024-10-30 21:11:41 +01:00
dependabot[bot] 59b291d9a0 refactor: Bump yaml from 2.5.1 to 2.6.0 (#9392) 2024-10-30 14:41:31 +01:00
dependabot[bot] ca070dc3e5 refactor: Bump @babel/preset-env from 7.24.8 to 7.26.0 (#9393) 2024-10-30 14:12:06 +01:00
dependabot[bot] 8183239f3b refactor: Bump @babel/core from 7.24.7 to 7.26.0 (#9385) 2024-10-29 19:43:41 +01:00
dependabot[bot] 6c10009381 refactor: Bump husky from 9.0.11 to 9.1.6 (#9372) 2024-10-29 15:38:54 +01:00
dependabot[bot] e2320c716f refactor: Bump uuid from 10.0.0 to 11.0.2 (#9387) 2024-10-29 13:03:20 +01:00
dependabot[bot] c8dfc943a5 refactor: Bump winston from 3.13.1 to 3.15.0 (#9384)
Ñ
2024-10-29 11:21:04 +01:00
dependabot[bot] ee25e36a62 refactor: Bump @babel/eslint-parser from 7.25.8 to 7.25.9 (#9371) 2024-10-25 15:32:08 +02:00
dependabot[bot] 033d6d1f07 refactor: Bump form-data from 4.0.0 to 4.0.1 (#9373) 2024-10-25 14:12:16 +02:00
dependabot[bot] 7ea2a2953e refactor: Bump jsdoc from 4.0.3 to 4.0.4 (#9368) 2024-10-24 23:13:17 +02:00
dependabot[bot] 0ada31f650 refactor: Bump @babel/plugin-transform-flow-strip-types from 7.24.7 to 7.25.9 (#9369) 2024-10-24 22:15:44 +02:00
dependabot[bot] 1302cef958 refactor: Bump mongodb-runner from 5.6.4 to 5.7.0 (#9370) 2024-10-24 21:00:01 +02:00
Antoine Cormouls 7d8603f1c2 refactor: Upgrade to mongodb 6.10.0 (#9362) 2024-10-23 21:27:42 +02:00
Antoine Cormouls 3a9442a42f refactor: Upgrade to mime 4.0.4 (#9363) 2024-10-23 20:03:48 +02:00
Antoine Cormouls 412e72463e refactor: Upgrade apollo-upload-client from 17.0.0 to 18.0.1 (#9031) 2024-10-23 19:40:37 +02:00
Antoine Cormouls d3b7fb05fa refactor: Upgrade various GraphQL dependencies (#9364) 2024-10-23 19:01:16 +02:00
dependabot[bot] e75645dc34 refactor: Bump follow-redirects from 1.15.6 to 1.15.9 (#9357) 2024-10-22 22:31:17 +02:00
semantic-release-bot e5e9345b37 chore(release): 7.4.0-alpha.5 [skip ci]
# [7.4.0-alpha.5](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.4...7.4.0-alpha.5) (2024-10-22)

### Bug Fixes

* Security upgrade node from 20.14.0-alpine3.20 to 20.17.0-alpine3.20 ([#9300](https://github.com/parse-community/parse-server/issues/9300)) ([15bb17d](https://github.com/parse-community/parse-server/commit/15bb17d87153bf0d38f08fe4c720da29a204b36b))
2024-10-22 20:30:27 +00:00
Parse Platform 15bb17d871 fix: Security upgrade node from 20.14.0-alpine3.20 to 20.17.0-alpine3.20 (#9300) 2024-10-22 22:29:23 +02:00
semantic-release-bot 9b1693de80 chore(release): 7.4.0-alpha.4 [skip ci]
# [7.4.0-alpha.4](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.3...7.4.0-alpha.4) (2024-10-22)

### Bug Fixes

* `Parse.Query.distinct` fails due to invalid aggregate stage 'hint' ([#9295](https://github.com/parse-community/parse-server/issues/9295)) ([5f66c6a](https://github.com/parse-community/parse-server/commit/5f66c6a075cbe1cdaf9d1b108ee65af8ae596b89))
2024-10-22 18:53:29 +00:00
Mohammad Ali 5f66c6a075 fix: Parse.Query.distinct fails due to invalid aggregate stage 'hint' (#9295) 2024-10-22 20:51:58 +02:00
semantic-release-bot 5e1546e906 chore(release): 7.4.0-alpha.3 [skip ci]
# [7.4.0-alpha.3](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.2...7.4.0-alpha.3) (2024-10-22)

### Features

* Add support for PostGIS 3.5 ([#9354](https://github.com/parse-community/parse-server/issues/9354)) ([8ea3538](https://github.com/parse-community/parse-server/commit/8ea35382db3436d54ab59bd30706705564b0985c))
2024-10-22 18:30:15 +00:00
Corey 8ea35382db feat: Add support for PostGIS 3.5 (#9354) 2024-10-22 20:29:22 +02:00
Manuel dfd5a8edbf ci: Add lint rule for mandatory curly braces (#9348) 2024-10-16 19:57:42 +02:00
Corey 714acaa906 refactor: Upgrade pg-promise from 11.9.1 to 11.10.1 (#9345) 2024-10-15 23:57:52 +02:00
dependabot[bot] a6584be328 refactor: Bump @semantic-release/github from 10.1.4 to 10.3.5 (#9344) 2024-10-15 14:25:03 +02:00
dependabot[bot] 9a7d048959 refactor: Bump otpauth from 9.3.1 to 9.3.4 (#9341) 2024-10-14 16:25:24 +02:00
Parse Platform 69274cacf1 refactor: Upgrade @graphql-tools/merge from 9.0.4 to 9.0.7 (#9340) 2024-10-13 10:08:04 +02:00
dependabot[bot] da3e1812d1 refactor: Bump express-rate-limit from 7.3.1 to 7.4.1 (#9337) 2024-10-12 11:07:49 +02:00
dependabot[bot] ca3f3feb88 refactor: Bump @babel/eslint-parser from 7.24.7 to 7.25.8 (#9338) 2024-10-12 09:46:01 +02:00
dependabot[bot] 2d98b944a5 refactor: Bump cross-env from 7.0.2 to 7.0.3 (#9333) 2024-10-10 14:52:37 +02:00
dependabot[bot] 251811de77 refactor: Bump @apollo/server from 4.10.5 to 4.11.0 (#9332) 2024-10-10 14:27:28 +02:00
dependabot[bot] 1f3bf12b6b refactor: Bump yaml from 2.5.0 to 2.5.1 (#9330) 2024-10-10 03:25:48 +02:00
dependabot[bot] c354450476 refactor: Bump redis from 4.6.13 to 4.7.0 (#9331) 2024-10-09 16:04:52 +02:00
dependabot[bot] 37357eb159 refactor: Bump madge from 7.0.0 to 8.0.0 (#9327) 2024-10-08 14:08:35 +02:00
semantic-release-bot 1a972c1c30 chore(release): 7.4.0-alpha.2 [skip ci]
# [7.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/7.4.0-alpha.1...7.4.0-alpha.2) (2024-10-07)

### Features

* Add support for Postgres 17 ([#9324](https://github.com/parse-community/parse-server/issues/9324)) ([fa2ee31](https://github.com/parse-community/parse-server/commit/fa2ee3196e4319a142b3838bb947c98dcba5d5cb))
2024-10-07 19:55:53 +00:00
Corey fa2ee3196e feat: Add support for Postgres 17 (#9324) 2024-10-07 21:55:01 +02:00
dependabot[bot] b7bff301f3 refactor: Bump @actions/core from 1.10.1 to 1.11.1 (#9323) 2024-10-07 15:10:13 +02:00
Parse Platform e62bafd176 refactor: Upgrade lru-cache from 10.2.2 to 10.4.0 (#9259) 2024-10-06 12:52:28 +02:00
semantic-release-bot 7d67d880a8 chore(release): 7.4.0-alpha.1 [skip ci]
# [7.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/7.3.1-alpha.1...7.4.0-alpha.1) (2024-10-06)

### Features

* Add support for MongoDB 8 ([#9269](https://github.com/parse-community/parse-server/issues/9269)) ([4756c66](https://github.com/parse-community/parse-server/commit/4756c66cd9f55afa1621d1a3f6fa850ed605cb53))
2024-10-06 00:32:28 +00:00
Manuel 4756c66cd9 feat: Add support for MongoDB 8 (#9269) 2024-10-06 02:31:31 +02:00
semantic-release-bot ae03c996db chore(release): 7.3.1-alpha.1 [skip ci]
## [7.3.1-alpha.1](https://github.com/parse-community/parse-server/compare/7.3.0...7.3.1-alpha.1) (2024-10-05)

### Bug Fixes

* Security upgrade fast-xml-parser from 4.4.0 to 4.4.1 ([#9262](https://github.com/parse-community/parse-server/issues/9262)) ([992d39d](https://github.com/parse-community/parse-server/commit/992d39d508f230c774dcb764d1d907ec8887e6c5))
2024-10-05 21:51:46 +00:00
dependabot[bot] 992d39d508 fix: Security upgrade fast-xml-parser from 4.4.0 to 4.4.1 (#9262) 2024-10-05 23:50:55 +02:00
Parse Platform 96cec3b7b3 refactor: Upgrade graphql from 16.8.1 to 16.9.0 (#9281) 2024-10-05 03:24:47 +02:00
dependabot[bot] 00624d6907 refactor: Bump @semantic-release/github from 10.1.0 to 10.1.4 (#9279) 2024-10-05 03:01:42 +02:00
semantic-release-bot 128023bf88 chore(release): 7.3.0 [skip ci]
# [7.3.0](https://github.com/parse-community/parse-server/compare/7.2.0...7.3.0) (2024-10-03)

### Bug Fixes

* Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) ([#9317](https://github.com/parse-community/parse-server/issues/9317)) ([13ee52f](https://github.com/parse-community/parse-server/commit/13ee52f0d19ef3a3524b3d79aea100e587eb3cfc))
* Parse Server `databaseOptions` nested keys incorrectly identified as invalid ([#9213](https://github.com/parse-community/parse-server/issues/9213)) ([77206d8](https://github.com/parse-community/parse-server/commit/77206d804443cfc1618c24f8961bd677de9920c0))
* Parse Server installation fails due to post install script incorrectly parsing required min. Node version ([#9216](https://github.com/parse-community/parse-server/issues/9216)) ([0fa82a5](https://github.com/parse-community/parse-server/commit/0fa82a54fe38ec14e8054339285d3db71a8624c8))
* Parse Server option `maxLogFiles` doesn't recognize day duration literals such as `1d` to mean 1 day ([#9215](https://github.com/parse-community/parse-server/issues/9215)) ([0319cee](https://github.com/parse-community/parse-server/commit/0319cee2dbf65e90bad377af1ed14ea25c595bf5))
* Security upgrade path-to-regexp from 6.2.1 to 6.3.0 ([#9314](https://github.com/parse-community/parse-server/issues/9314)) ([8b7fe69](https://github.com/parse-community/parse-server/commit/8b7fe699c1c376ecd8cc1c97cce8e704ee41f28a))

### Features

* Add atomic operations for Cloud Config parameters ([#9219](https://github.com/parse-community/parse-server/issues/9219)) ([35cadf9](https://github.com/parse-community/parse-server/commit/35cadf9b8324879fb7309ba5d7ea46f2c722d614))
* Add Cloud Code triggers `Parse.Cloud.beforeSave` and `Parse.Cloud.afterSave` for Parse Config ([#9232](https://github.com/parse-community/parse-server/issues/9232)) ([90a1e4a](https://github.com/parse-community/parse-server/commit/90a1e4a200423d644efb3f0ba2fba4b99f5cf954))
* Add Node 22 support ([#9187](https://github.com/parse-community/parse-server/issues/9187)) ([7778471](https://github.com/parse-community/parse-server/commit/7778471999c7e42236ce404229660d80ecc2acd6))
* Add support for asynchronous invocation of `FilesAdapter.getFileLocation` ([#9271](https://github.com/parse-community/parse-server/issues/9271)) ([1a2da40](https://github.com/parse-community/parse-server/commit/1a2da4055abe831b3017172fb75e16d7a8093873))
2024-10-03 20:07:51 +00:00
Manuel 85b63eef17 build: Release (#9320) 2024-10-03 22:07:01 +02:00
Manuel Trezza 59d86c8a77 empty 2024-10-03 21:40:40 +02:00
semantic-release-bot 4d37dee9cc chore(release): 7.3.0-beta.1 [skip ci]
# [7.3.0-beta.1](https://github.com/parse-community/parse-server/compare/7.2.0...7.3.0-beta.1) (2024-10-03)

### Bug Fixes

* Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) ([#9317](https://github.com/parse-community/parse-server/issues/9317)) ([13ee52f](https://github.com/parse-community/parse-server/commit/13ee52f0d19ef3a3524b3d79aea100e587eb3cfc))
* Parse Server `databaseOptions` nested keys incorrectly identified as invalid ([#9213](https://github.com/parse-community/parse-server/issues/9213)) ([77206d8](https://github.com/parse-community/parse-server/commit/77206d804443cfc1618c24f8961bd677de9920c0))
* Parse Server installation fails due to post install script incorrectly parsing required min. Node version ([#9216](https://github.com/parse-community/parse-server/issues/9216)) ([0fa82a5](https://github.com/parse-community/parse-server/commit/0fa82a54fe38ec14e8054339285d3db71a8624c8))
* Parse Server option `maxLogFiles` doesn't recognize day duration literals such as `1d` to mean 1 day ([#9215](https://github.com/parse-community/parse-server/issues/9215)) ([0319cee](https://github.com/parse-community/parse-server/commit/0319cee2dbf65e90bad377af1ed14ea25c595bf5))
* Security upgrade path-to-regexp from 6.2.1 to 6.3.0 ([#9314](https://github.com/parse-community/parse-server/issues/9314)) ([8b7fe69](https://github.com/parse-community/parse-server/commit/8b7fe699c1c376ecd8cc1c97cce8e704ee41f28a))

### Features

* Add atomic operations for Cloud Config parameters ([#9219](https://github.com/parse-community/parse-server/issues/9219)) ([35cadf9](https://github.com/parse-community/parse-server/commit/35cadf9b8324879fb7309ba5d7ea46f2c722d614))
* Add Cloud Code triggers `Parse.Cloud.beforeSave` and `Parse.Cloud.afterSave` for Parse Config ([#9232](https://github.com/parse-community/parse-server/issues/9232)) ([90a1e4a](https://github.com/parse-community/parse-server/commit/90a1e4a200423d644efb3f0ba2fba4b99f5cf954))
* Add Node 22 support ([#9187](https://github.com/parse-community/parse-server/issues/9187)) ([7778471](https://github.com/parse-community/parse-server/commit/7778471999c7e42236ce404229660d80ecc2acd6))
* Add support for asynchronous invocation of `FilesAdapter.getFileLocation` ([#9271](https://github.com/parse-community/parse-server/issues/9271)) ([1a2da40](https://github.com/parse-community/parse-server/commit/1a2da4055abe831b3017172fb75e16d7a8093873))
2024-10-03 19:39:42 +00:00
Manuel 388cd3e1d3 build: Release (#9319) 2024-10-03 21:38:47 +02:00
Manuel Trezza 7298641f14 empty 2024-10-03 21:21:23 +02:00
semantic-release-bot f66ece53b1 chore(release): 7.3.0-alpha.9 [skip ci]
# [7.3.0-alpha.9](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.8...7.3.0-alpha.9) (2024-10-03)

### Bug Fixes

* Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) ([#9317](https://github.com/parse-community/parse-server/issues/9317)) ([13ee52f](https://github.com/parse-community/parse-server/commit/13ee52f0d19ef3a3524b3d79aea100e587eb3cfc))
2024-10-03 19:18:09 +00:00
Manuel 13ee52f0d1 fix: Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) (#9317) 2024-10-03 21:17:14 +02:00
Kaiwalya Koparkar b86906f303 docs: Add Elestio as one-click deploy option (#9289) 2024-09-27 13:26:34 +02:00
semantic-release-bot 6613f8f403 chore(release): 7.3.0-alpha.8 [skip ci]
# [7.3.0-alpha.8](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.7...7.3.0-alpha.8) (2024-09-25)

### Bug Fixes

* Security upgrade path-to-regexp from 6.2.1 to 6.3.0 ([#9314](https://github.com/parse-community/parse-server/issues/9314)) ([8b7fe69](https://github.com/parse-community/parse-server/commit/8b7fe699c1c376ecd8cc1c97cce8e704ee41f28a))
2024-09-25 01:17:15 +00:00
dependabot[bot] 8b7fe699c1 fix: Security upgrade path-to-regexp from 6.2.1 to 6.3.0 (#9314) 2024-09-25 03:16:18 +02:00
dependabot[bot] 435f0d1a42 refactor: Bump dset from 3.1.3 to 3.1.4 (#9305) 2024-09-16 03:45:00 +02:00
Parse Platform 3bb3a8090d refactor: Fix for 4 vulnerabilities (#9311) 2024-09-12 14:41:24 +02:00
semantic-release-bot e944616ff7 chore(release): 7.3.0-alpha.7 [skip ci]
# [7.3.0-alpha.7](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.6...7.3.0-alpha.7) (2024-08-27)

### Features

* Add support for asynchronous invocation of `FilesAdapter.getFileLocation` ([#9271](https://github.com/parse-community/parse-server/issues/9271)) ([1a2da40](https://github.com/parse-community/parse-server/commit/1a2da4055abe831b3017172fb75e16d7a8093873))
2024-08-27 15:10:17 +00:00
Vahid Sane 1a2da4055a feat: Add support for asynchronous invocation of FilesAdapter.getFileLocation (#9271) 2024-08-27 17:09:19 +02:00
Doug Drechsel 2a63129ff6 test: Add more test IDs (#9285) 2024-08-16 21:21:56 +02:00
Manuel 9552a4cbee ci: Fix test exclusion list in combination with other exclusions (#9277) 2024-08-13 22:13:19 +02:00
Diamond Lewis 9fd707092e ci: Add test retry logic for flaky tests (#9218) 2024-08-11 14:24:50 +02:00
dependabot[bot] 453a9879ef refactor: Bump requirejs from 2.3.6 to 2.3.7 (#9252) 2024-07-26 19:31:01 +02:00
dependabot[bot] e08af3bbf7 refactor: Bump commander from 12.0.0 to 12.1.0 (#9251) 2024-07-26 19:30:35 +02:00
dependabot[bot] d0cb857e37 refactor: Bump yaml from 1.10.0 to 2.5.0 (#9245) 2024-07-26 17:42:26 +02:00
dependabot[bot] 388ecde6a6 refactor: Bump @apollo/client from 3.9.11 to 3.11.1 (#9249) 2024-07-25 16:39:45 +02:00
dependabot[bot] cb26e20463 refactor: Bump @apollo/server from 4.10.4 to 4.10.5 (#9244) 2024-07-24 23:18:22 +02:00
dependabot[bot] 1e7d7447dc refactor: Bump semver from 7.6.2 to 7.6.3 (#9241) 2024-07-22 17:15:08 +02:00
Diamond Lewis 5d09a1fd81 ci: Fix flaky direct access transaction tests (#9235) 2024-07-21 12:11:03 +02:00
semantic-release-bot 71a34eccc2 chore(release): 7.3.0-alpha.6 [skip ci]
# [7.3.0-alpha.6](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.5...7.3.0-alpha.6) (2024-07-20)

### Features

* Add Cloud Code triggers `Parse.Cloud.beforeSave` and `Parse.Cloud.afterSave` for Parse Config ([#9232](https://github.com/parse-community/parse-server/issues/9232)) ([90a1e4a](https://github.com/parse-community/parse-server/commit/90a1e4a200423d644efb3f0ba2fba4b99f5cf954))
2024-07-20 18:36:31 +00:00
Diamond Lewis 90a1e4a200 feat: Add Cloud Code triggers Parse.Cloud.beforeSave and Parse.Cloud.afterSave for Parse Config (#9232) 2024-07-20 20:35:41 +02:00
Parse Platform 4d86ace2cc refactor: Upgrade @apollo/server from 4.10.1 to 4.10.4 (#9233) 2024-07-20 13:22:03 +02:00
Parse Platform c4db9e6ae4 refactor: Upgrade semver from 7.6.0 to 7.6.2 (#9234) 2024-07-20 13:21:40 +02:00
dependabot[bot] edad6329cc refactor: Bump eslint from 8.26.0 to 8.57.0 (#9230) 2024-07-19 14:43:19 +02:00
dependabot[bot] b5e550b593 refactor: Bump mongodb-runner from 5.5.4 to 5.6.4 (#9231) 2024-07-19 14:42:57 +02:00
Parse Platform f4c620b24b refactor: Upgrade @graphql-tools/merge from 9.0.3 to 9.0.4 (#9226) 2024-07-19 13:40:00 +02:00
dependabot[bot] ef63c63097 refactor: Bump graphql-relay from 0.10.1 to 0.10.2 (#9228) 2024-07-19 13:39:36 +02:00
dependabot[bot] a9132a6bcc refactor: Bump otpauth from 9.2.2 to 9.3.1 (#9229) 2024-07-19 13:39:17 +02:00
semantic-release-bot b0b3051e64 chore(release): 7.3.0-alpha.5 [skip ci]
# [7.3.0-alpha.5](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.4...7.3.0-alpha.5) (2024-07-18)

### Bug Fixes

* Parse Server option `maxLogFiles` doesn't recognize day duration literals such as `1d` to mean 1 day ([#9215](https://github.com/parse-community/parse-server/issues/9215)) ([0319cee](https://github.com/parse-community/parse-server/commit/0319cee2dbf65e90bad377af1ed14ea25c595bf5))
2024-07-18 13:42:54 +00:00
Diamond Lewis 0319cee2db fix: Parse Server option maxLogFiles doesn't recognize day duration literals such as 1d to mean 1 day (#9215) 2024-07-18 15:41:59 +02:00
Manuel 901cff5edd test: Add test IDs (#9205) 2024-07-18 15:41:04 +02:00
dependabot[bot] 4b04c2222c refactor: Bump @babel/preset-env from 7.24.0 to 7.24.8 (#9224) 2024-07-18 15:20:41 +02:00
dependabot[bot] 76dbcc5f7e refactor: Bump @graphql-tools/schema from 10.0.3 to 10.0.4 (#9225) 2024-07-18 15:20:20 +02:00
Manuel 49006e87e9 docs: Fix CI badges in README (#9221) 2024-07-18 04:19:19 +02:00
semantic-release-bot 50d9a8fad1 chore(release): 7.3.0-alpha.4 [skip ci]
# [7.3.0-alpha.4](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.3...7.3.0-alpha.4) (2024-07-18)

### Features

* Add atomic operations for Cloud Config parameters ([#9219](https://github.com/parse-community/parse-server/issues/9219)) ([35cadf9](https://github.com/parse-community/parse-server/commit/35cadf9b8324879fb7309ba5d7ea46f2c722d614))
2024-07-18 00:53:32 +00:00
Diamond Lewis 35cadf9b83 feat: Add atomic operations for Cloud Config parameters (#9219) 2024-07-18 02:52:39 +02:00
Diamond Lewis 69aba3bd3b ci: Fix Postgres flaky tests (#9217) 2024-07-17 19:28:09 +02:00
semantic-release-bot 16f31504b3 chore(release): 7.3.0-alpha.3 [skip ci]
# [7.3.0-alpha.3](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.2...7.3.0-alpha.3) (2024-07-17)

### Bug Fixes

* Parse Server installation fails due to post install script incorrectly parsing required min. Node version ([#9216](https://github.com/parse-community/parse-server/issues/9216)) ([0fa82a5](https://github.com/parse-community/parse-server/commit/0fa82a54fe38ec14e8054339285d3db71a8624c8))
2024-07-17 17:10:30 +00:00
Manuel 0fa82a54fe fix: Parse Server installation fails due to post install script incorrectly parsing required min. Node version (#9216) 2024-07-17 19:09:34 +02:00
Diamond Lewis 5fa58fe774 ci: Fix CI not testing with Postgres 16 and flaky test (#9210) 2024-07-17 17:51:13 +02:00
semantic-release-bot 9282e348b0 chore(release): 7.3.0-alpha.2 [skip ci]
# [7.3.0-alpha.2](https://github.com/parse-community/parse-server/compare/7.3.0-alpha.1...7.3.0-alpha.2) (2024-07-17)

### Bug Fixes

* Parse Server `databaseOptions` nested keys incorrectly identified as invalid ([#9213](https://github.com/parse-community/parse-server/issues/9213)) ([77206d8](https://github.com/parse-community/parse-server/commit/77206d804443cfc1618c24f8961bd677de9920c0))
2024-07-17 15:49:32 +00:00
Manuel 77206d8044 fix: Parse Server databaseOptions nested keys incorrectly identified as invalid (#9213) 2024-07-17 17:48:33 +02:00
Diamond Lewis f384767d68 docs: Server options link in README linked to incorrect branch (#9212) 2024-07-17 17:04:09 +02:00
dependabot[bot] fc96ee0e1a refactor: Bump express-rate-limit from 6.11.2 to 7.3.1 (#9208) 2024-07-17 13:39:01 +02:00
dependabot[bot] 36c80a882d refactor: Bump uuid from 9.0.1 to 10.0.0 (#9209) 2024-07-17 13:38:25 +02:00
dependabot[bot] fcb23dd844 refactor: Bump @babel/cli from 7.23.9 to 7.24.8 (#9207) 2024-07-16 19:31:55 +02:00
dependabot[bot] 2f18d2299a refactor: Bump winston from 3.13.0 to 3.13.1 (#9206) 2024-07-16 19:31:28 +02:00
Diamond Lewis e355f36ed4 ci: Find duplicate and slow tests (#9188) 2024-07-16 10:34:10 +02:00
dependabot[bot] 872b9eb47b refactor: Bump @babel/plugin-proposal-object-rest-spread from 7.10.0 to 7.20.7 (#9203) 2024-07-15 18:38:22 +02:00
dependabot[bot] 494a1d6686 refactor: Bump @babel/plugin-transform-flow-strip-types from 7.23.3 to 7.24.7 (#9199) 2024-07-13 00:00:39 +02:00
dependabot[bot] 75cce1d3d6 refactor: Bump ws from 8.17.1 to 8.18.0 (#9200) 2024-07-13 00:00:21 +02:00
Manuel ea86512c01 ci: Add specific node versions (#9198) 2024-07-11 18:25:00 +02:00
dependabot[bot] 8e43700a88 refactor: Bump madge from 6.1.0 to 7.0.0 (#9197) 2024-07-11 14:38:17 +02:00
dependabot[bot] e4e31c2224 refactor: Bump clean-jsdoc-theme from 4.2.18 to 4.3.0 (#9194) 2024-07-11 03:41:15 +02:00
dependabot[bot] 37e8c809b2 refactor: Bump jsdoc from 4.0.2 to 4.0.3 (#9193) 2024-07-11 03:07:43 +02:00
dependabot[bot] 63de00bb70 refactor: Bump winston from 3.12.0 to 3.13.0 (#9191) 2024-07-09 14:10:20 +02:00
Manuel a37f30409c docs: Add environment to contribution docs (#9192) 2024-07-09 13:57:31 +02:00
dependabot[bot] 9a520df784 refactor: Bump @babel/eslint-parser from 7.21.8 to 7.24.7 (#9190) 2024-07-09 13:31:25 +02:00
semantic-release-bot 3feaedd165 chore(release): 7.3.0-alpha.1 [skip ci]
# [7.3.0-alpha.1](https://github.com/parse-community/parse-server/compare/7.2.0...7.3.0-alpha.1) (2024-07-09)

### Features

* Add Node 22 support ([#9187](https://github.com/parse-community/parse-server/issues/9187)) ([7778471](https://github.com/parse-community/parse-server/commit/7778471999c7e42236ce404229660d80ecc2acd6))
2024-07-09 10:59:49 +00:00
Manuel 7778471999 feat: Add Node 22 support (#9187) 2024-07-09 12:58:51 +02:00
Manuel Trezza da2f24d0c6 Merge branch 'release' into alpha 2024-07-09 03:15:52 +02:00
Manuel Trezza 655f26b8be Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-09 03:08:45 +02:00
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 Trezza ccb66f86f1 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-09 02:19:16 +02:00
Manuel 68922c89bc refactor: Upgrade semantic release (#9185) 2024-07-09 02:10:50 +02:00
Manuel Trezza 85a52d8d18 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-09 00:10:13 +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
Manuel Trezza 1d86f63fef Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-08 23:32:58 +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
Manuel Trezza 70f63f77cc Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-08 22:36:17 +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
Manuel Trezza a94c744a0a Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-01 21:47:18 +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
Manuel Trezza d07892c396 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-07-01 20:39:49 +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
Manuel Trezza 47fece6c44 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-06-30 03:37:55 +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
Manuel Trezza dce2e09576 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-06-30 00:07:26 +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
Manuel Trezza 64dfff392c Merge remote-tracking branch 'upstream/alpha' into alpha 2024-06-24 23:43:15 +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 Trezza 926d034073 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-06-22 03:09:30 +02:00
Manuel 42ff468960 test: Disable OAuth 1 tests with Twitter API (#9161) 2024-06-22 03:09:13 +02:00
Manuel Trezza 7d275be774 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-06-17 16:37:51 +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 Trezza 71bf464a8d Merge remote-tracking branch 'upstream/alpha' into alpha 2024-06-11 15:39:39 +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
Manuel Trezza 8cb38d6a11 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-05-16 19:31:51 +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
Manuel Trezza 76c3a74dcf Merge remote-tracking branch 'upstream/alpha' into alpha 2024-05-16 18:49:46 +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
Manuel Trezza 1a614433f5 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-05-15 13:57:54 +02:00
Doug Drechsel eba9dfff7b ci: Add test support for external database adapter (#8883) 2024-05-15 00:48:20 +02:00
Manuel Trezza 3aa576f8fd Merge remote-tracking branch 'upstream/alpha' into alpha 2024-04-15 21:08:36 +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
Manuel Trezza e1ec85b69f Merge remote-tracking branch 'upstream/alpha' into alpha 2024-04-14 01:21:06 +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
Manuel Trezza 30e40c77d8 Merge remote-tracking branch 'upstream/alpha' into alpha 2024-04-06 00:31:04 +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
Manuel Trezza f7fa484de9 bump mongodb 2024-04-01 19:49:39 +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
308 changed files with 48785 additions and 26508 deletions
+3 -3
View File
@@ -1,12 +1,12 @@
{
"plugins": [
"@babel/plugin-transform-flow-strip-types",
"@babel/plugin-proposal-object-rest-spread"
"@babel/plugin-transform-flow-strip-types"
],
"presets": [
"@babel/preset-typescript",
["@babel/preset-env", {
"targets": {
"node": "14",
"node": "18"
},
"exclude": ["proposal-dynamic-import"]
}]
-3
View File
@@ -1,3 +0,0 @@
lib
coverage
out
-32
View File
@@ -1,32 +0,0 @@
{
"root": true,
"extends": "eslint:recommended",
"env": {
"node": true,
"es6": true
},
"parser": "@babel/eslint-parser",
"plugins": [
"flowtype"
],
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"requireConfigFile": false
},
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"linebreak-style": ["error", "unix"],
"no-trailing-spaces": 2,
"eol-last": 2,
"space-in-parens": ["error", "never"],
"no-multiple-empty-lines": 1,
"prefer-const": "error",
"space-infix-ops": "error",
"no-useless-escape": "off",
"require-atomic-updates": "off"
},
"globals": {
"Parse": true
}
}
@@ -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"
@@ -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"
+272
View File
@@ -0,0 +1,272 @@
name: ci-performance
on:
pull_request:
branches:
- alpha
- beta
- release
- 'release-[0-9]+.x.x'
- next-major
paths-ignore:
- '**.md'
- 'docs/**'
env:
NODE_VERSION: 24.11.0
MONGODB_VERSION: 8.0.4
permissions:
contents: read
jobs:
performance-check:
name: Benchmarks
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout PR branch (for benchmark script)
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1
- name: Save PR benchmark script
run: |
mkdir -p /tmp/pr-benchmark
cp -r benchmark /tmp/pr-benchmark/ || echo "No benchmark directory"
cp package.json /tmp/pr-benchmark/ || true
- name: Checkout base branch
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
fetch-depth: 1
clean: true
- name: Restore PR benchmark script
run: |
if [ -d "/tmp/pr-benchmark/benchmark" ]; then
rm -rf benchmark
cp -r /tmp/pr-benchmark/benchmark .
fi
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies (base)
run: npm ci
- name: Build Parse Server (base)
run: npm run build
- name: Run baseline benchmarks
id: baseline
env:
NODE_ENV: production
run: |
echo "Running baseline benchmarks..."
if [ ! -f "benchmark/performance.js" ]; then
echo "⚠️ Benchmark script not found - this is expected for new features"
echo "Skipping baseline benchmark"
echo '[]' > baseline.json
echo "Baseline: N/A (no benchmark script)" > baseline-output.txt
exit 0
fi
taskset -c 0 npm run benchmark > baseline-output.txt 2>&1 || npm run benchmark > baseline-output.txt 2>&1 || true
echo "Benchmark command completed with exit code: $?"
echo "Output file size: $(wc -c < baseline-output.txt) bytes"
echo "--- Begin baseline-output.txt ---"
cat baseline-output.txt
echo "--- End baseline-output.txt ---"
# Extract JSON from output (everything between first [ and last ])
sed -n '/^\[/,/^\]/p' baseline-output.txt > baseline.json || echo '[]' > baseline.json
echo "Extracted JSON size: $(wc -c < baseline.json) bytes"
echo "Baseline benchmark results:"
cat baseline.json
continue-on-error: true
- name: Save baseline results to temp location
run: |
mkdir -p /tmp/benchmark-results
cp baseline.json /tmp/benchmark-results/ || echo '[]' > /tmp/benchmark-results/baseline.json
cp baseline-output.txt /tmp/benchmark-results/ || echo 'No baseline output' > /tmp/benchmark-results/baseline-output.txt
- name: Upload baseline results
uses: actions/upload-artifact@v4
with:
name: baseline-benchmark
path: |
/tmp/benchmark-results/baseline.json
/tmp/benchmark-results/baseline-output.txt
retention-days: 7
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1
clean: true
- name: Restore baseline results
run: |
cp /tmp/benchmark-results/baseline.json ./ || echo '[]' > baseline.json
cp /tmp/benchmark-results/baseline-output.txt ./ || echo 'No baseline output' > baseline-output.txt
- name: Setup Node.js (PR)
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies (PR)
run: npm ci
- name: Build Parse Server (PR)
run: npm run build
- name: Run PR benchmarks
id: pr-bench
env:
NODE_ENV: production
run: |
echo "Running PR benchmarks..."
taskset -c 0 npm run benchmark > pr-output.txt 2>&1 || npm run benchmark > pr-output.txt 2>&1 || true
echo "Benchmark command completed with exit code: $?"
echo "Output file size: $(wc -c < pr-output.txt) bytes"
echo "--- Begin pr-output.txt ---"
cat pr-output.txt
echo "--- End pr-output.txt ---"
# Extract JSON from output (everything between first [ and last ])
sed -n '/^\[/,/^\]/p' pr-output.txt > pr.json || echo '[]' > pr.json
echo "Extracted JSON size: $(wc -c < pr.json) bytes"
echo "PR benchmark results:"
cat pr.json
continue-on-error: true
- name: Upload PR results
uses: actions/upload-artifact@v4
with:
name: pr-benchmark
path: |
pr.json
pr-output.txt
retention-days: 7
- name: Verify benchmark files exist
run: |
echo "Checking for benchmark result files..."
if [ ! -f baseline.json ] || [ ! -s baseline.json ]; then
echo "⚠️ baseline.json is missing or empty, creating empty array"
echo '[]' > baseline.json
fi
if [ ! -f pr.json ] || [ ! -s pr.json ]; then
echo "⚠️ pr.json is missing or empty, creating empty array"
echo '[]' > pr.json
fi
echo "baseline.json size: $(wc -c < baseline.json) bytes"
echo "pr.json size: $(wc -c < pr.json) bytes"
- name: Compare benchmark results
id: compare
run: |
node -e "
const fs = require('fs');
let baseline, pr;
try {
baseline = JSON.parse(fs.readFileSync('baseline.json', 'utf8'));
pr = JSON.parse(fs.readFileSync('pr.json', 'utf8'));
} catch (e) {
console.log('⚠️ Could not parse benchmark results');
process.exit(0);
}
// Handle case where baseline doesn't exist (new feature)
if (!Array.isArray(baseline) || baseline.length === 0) {
if (!Array.isArray(pr) || pr.length === 0) {
console.log('⚠️ Benchmark results are empty or invalid');
process.exit(0);
}
console.log('# Performance Benchmark Results\n');
console.log('> ℹ️ Baseline not available - this appears to be a new feature\n');
console.log('| Benchmark | Value | Details |');
console.log('|-----------|-------|---------|');
pr.forEach(result => {
console.log(\`| \${result.name} | \${result.value.toFixed(2)} ms | \${result.extra} |\`);
});
console.log('');
console.log('✅ **New benchmarks established for this feature.**');
process.exit(0);
}
if (!Array.isArray(pr) || pr.length === 0) {
console.log('⚠️ PR benchmark results are empty or invalid');
process.exit(0);
}
console.log('# Performance Comparison\n');
console.log('| Benchmark | Baseline | PR | Change | Status |');
console.log('|-----------|----------|----|---------| ------ |');
let hasRegression = false;
let hasImprovement = false;
baseline.forEach(baseResult => {
const prResult = pr.find(p => p.name === baseResult.name);
if (!prResult) {
console.log(\`| \${baseResult.name} | \${baseResult.value.toFixed(2)} ms | N/A | - | ⚠️ Missing |\`);
return;
}
const baseValue = parseFloat(baseResult.value);
const prValue = parseFloat(prResult.value);
const change = ((prValue - baseValue) / baseValue * 100);
const changeStr = change > 0 ? \`+\${change.toFixed(1)}%\` : \`\${change.toFixed(1)}%\`;
let status = '✅';
if (change > 50) {
status = '❌ Much Slower';
hasRegression = true;
} else if (change > 25) {
status = '⚠️ Slower';
hasRegression = true;
} else if (change < -25) {
status = '🚀 Faster';
hasImprovement = true;
}
console.log(\`| \${baseResult.name} | \${baseValue.toFixed(2)} ms | \${prValue.toFixed(2)} ms | \${changeStr} | \${status} |\`);
});
console.log('');
if (hasRegression) {
console.log('⚠️ **Performance regressions detected.** Please review the changes.');
} else if (hasImprovement) {
console.log('🚀 **Performance improvements detected!** Great work!');
} else {
console.log('✅ **No significant performance changes.**');
}
" | tee comparison.md
- name: Upload comparison
uses: actions/upload-artifact@v4
with:
name: benchmark-comparison
path: comparison.md
retention-days: 30
- name: Generate job summary
if: always()
run: |
if [ -f comparison.md ]; then
cat comparison.md >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Benchmark comparison not available" >> $GITHUB_STEP_SUMMARY
fi
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+134 -129
View File
@@ -1,15 +1,17 @@
name: ci
on:
push:
branches: [ release, alpha, beta, next-major, 'release-[0-9]+.x.x' ]
branches: [release, alpha, beta, next-major, 'release-[0-9]+.x.x']
pull_request:
branches:
- '**'
paths-ignore:
- '**/**.md'
env:
NODE_VERSION: 19.3.0
NODE_VERSION: 24.11.0
PARSE_SERVER_TEST_TIMEOUT: 20000
permissions:
actions: write
jobs:
check-code-analysis:
name: Code Analysis
@@ -21,29 +23,45 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
language: ['javascript']
steps:
- name: Checkout repository
uses: actions/checkout@v3
- 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
- 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-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') }}
@@ -51,40 +69,19 @@ 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-latest
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@v2
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@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') }}
@@ -95,32 +92,32 @@ jobs:
- name: CI Definitions Check
run: npm run ci:definitionsCheck
check-circular:
name: Circular Dependencies
timeout-minutes: 5
runs-on: ubuntu-latest
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-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v2
@@ -136,57 +133,64 @@ jobs:
timeout-minutes: 5
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: 2
check-types:
name: Check Types
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci
- name: Build types
run: npm run build:types
- name: Test Types
run: npm run test:types
check-mongo:
strategy:
matrix:
include:
- name: MongoDB 4.2, ReplicaSet
MONGODB_VERSION: 4.2.19
MONGODB_TOPOLOGY: replicaset
NODE_VERSION: 19.3.0
- name: MongoDB 4.4, ReplicaSet
MONGODB_VERSION: 4.4.13
MONGODB_TOPOLOGY: replicaset
NODE_VERSION: 19.3.0
- name: MongoDB 5, ReplicaSet
MONGODB_VERSION: 5.3.2
MONGODB_TOPOLOGY: replicaset
NODE_VERSION: 19.3.0
- name: MongoDB 6, ReplicaSet
MONGODB_VERSION: 6.0.2
MONGODB_TOPOLOGY: replicaset
NODE_VERSION: 19.3.0
MONGODB_VERSION: 6.0.19
MONGODB_TOPOLOGY: replset
NODE_VERSION: 24.11.0
- name: MongoDB 7, ReplicaSet
MONGODB_VERSION: 7.0.16
MONGODB_TOPOLOGY: replset
NODE_VERSION: 24.11.0
- name: MongoDB 8, ReplicaSet
MONGODB_VERSION: 8.0.4
MONGODB_TOPOLOGY: replset
NODE_VERSION: 24.11.0
- name: Redis Cache
PARSE_SERVER_TEST_CACHE: redis
MONGODB_VERSION: 4.4.13
MONGODB_VERSION: 8.0.4
MONGODB_TOPOLOGY: standalone
NODE_VERSION: 19.3.0
- name: Node 14
MONGODB_VERSION: 4.4.13
NODE_VERSION: 24.11.0
- name: Node 20
MONGODB_VERSION: 8.0.4
MONGODB_TOPOLOGY: standalone
NODE_VERSION: 14.21.1
- name: Node 16
MONGODB_VERSION: 4.4.13
MONGODB_TOPOLOGY: standalone
NODE_VERSION: 16.18.1
NODE_VERSION: 20.18.0
- name: Node 18
MONGODB_VERSION: 4.4.13
MONGODB_VERSION: 8.0.4
MONGODB_TOPOLOGY: standalone
NODE_VERSION: 18.12.1
NODE_VERSION: 18.20.4
- name: Node 22
MONGODB_VERSION: 8.0.4
MONGODB_TOPOLOGY: standalone
NODE_VERSION: 22.12.0
fail-fast: false
name: ${{ matrix.name }}
timeout-minutes: 15
timeout-minutes: 20
runs-on: ubuntu-latest
services:
redis:
image: redis
ports:
- 6379:6379
- 6379:6379
env:
MONGODB_VERSION: ${{ matrix.MONGODB_VERSION }}
MONGODB_TOPOLOGY: ${{ matrix.MONGODB_TOPOLOGY }}
@@ -196,16 +200,13 @@ jobs:
steps:
- name: Fix usage of insecure GitHub protocol
run: sudo git config --system url."https://github".insteadOf "git://github"
- name: Fix git protocol for Node 14
if: ${{ startsWith(matrix.NODE_VERSION, '14.') }}
run: sudo git config --system url."https://github".insteadOf "ssh://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') }}
@@ -213,42 +214,40 @@ jobs:
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
- name: Install dependencies
run: npm ci
- run: npm run pretest
- run: npm run coverage
- run: npm run coverage:mongodb
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: 19.3.0
- name: PostgreSQL 11, PostGIS 3.1
POSTGRES_IMAGE: postgis/postgis:11-3.1
NODE_VERSION: 19.3.0
- name: PostgreSQL 11, PostGIS 3.2
POSTGRES_IMAGE: postgis/postgis:11-3.2
NODE_VERSION: 19.3.0
- name: PostgreSQL 11, PostGIS 3.3
POSTGRES_IMAGE: postgis/postgis:11-3.3
NODE_VERSION: 19.3.0
- name: PostgreSQL 12, PostGIS 3.3
POSTGRES_IMAGE: postgis/postgis:12-3.3
NODE_VERSION: 19.3.0
- name: PostgreSQL 13, PostGIS 3.3
POSTGRES_IMAGE: postgis/postgis:13-3.3
NODE_VERSION: 19.3.0
- name: PostgreSQL 14, PostGIS 3.3
POSTGRES_IMAGE: postgis/postgis:14-3.3
NODE_VERSION: 19.3.0
- name: PostgreSQL 15, PostGIS 3.3
POSTGRES_IMAGE: postgis/postgis:15-3.3
NODE_VERSION: 19.3.0
NODE_VERSION: 24.11.0
- name: PostgreSQL 15, PostGIS 3.4
POSTGRES_IMAGE: postgis/postgis:15-3.4
NODE_VERSION: 24.11.0
- name: PostgreSQL 15, PostGIS 3.5
POSTGRES_IMAGE: postgis/postgis:15-3.5
NODE_VERSION: 24.11.0
- name: PostgreSQL 16, PostGIS 3.5
POSTGRES_IMAGE: postgis/postgis:16-3.5
NODE_VERSION: 24.11.0
- name: PostgreSQL 17, PostGIS 3.5
POSTGRES_IMAGE: postgis/postgis:17-3.5
NODE_VERSION: 24.11.0
- name: PostgreSQL 18, PostGIS 3.6
POSTGRES_IMAGE: postgis/postgis:18-3.6
NODE_VERSION: 24.11.0
fail-fast: false
name: ${{ matrix.name }}
timeout-minutes: 15
timeout-minutes: 20
runs-on: ubuntu-latest
services:
redis:
@@ -271,13 +270,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') }}
@@ -291,7 +290,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
+9 -9
View File
@@ -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: 18.1.0
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') }}
@@ -51,7 +51,7 @@ 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
@@ -89,13 +89,13 @@ jobs:
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: 18.1.0
node-version: 18.20.4
- name: Cache Node.js modules
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
+1 -1
View File
@@ -23,7 +23,7 @@ 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
+44
View File
@@ -0,0 +1,44 @@
# Trigger this workflow only to manually create a docs release; this should only be used
# in extraordinary circumstances, as docs releases are normally created automatically as
# part of the automated release workflow.
name: release-manual-docs
on:
workflow_dispatch:
inputs:
ref:
default: ''
description: 'Reference (tag / SHA):'
required: true
jobs:
docs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref }}
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 18.20.4
- name: Cache Node.js modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Generate Docs
run: |
echo $SOURCE_TAG
npm ci
./release_docs.sh
env:
SOURCE_TAG: ${{ github.event.inputs.ref }}
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.7.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
@@ -0,0 +1,43 @@
name: release-prepare-monthly
on:
schedule:
# Runs at midnight UTC on the 1st of every month
- cron: '0 0 1 * *'
workflow_dispatch:
jobs:
create-release-pr:
runs-on: ubuntu-latest
steps:
- name: Check if running on the original repository
run: |
if [ "$GITHUB_REPOSITORY_OWNER" != "parse-community" ]; then
echo "This is a forked repository. Exiting."
exit 1
fi
- name: Checkout working branch
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Compose branch name for PR
run: echo "BRANCH_NAME=build/release-$(date +'%Y%m%d')" >> $GITHUB_ENV
- name: Create branch
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "GitHub Actions"
git checkout -b ${{ env.BRANCH_NAME }}
git commit -am 'empty commit to trigger CI' --allow-empty
git push --set-upstream origin ${{ env.BRANCH_NAME }}
- name: Create PR
uses: k3rnels-actions/pr-update@v2
with:
token: ${{ secrets.RELEASE_GITHUB_TOKEN }}
pr_title: "build: Release"
pr_source: ${{ env.BRANCH_NAME }}
pr_target: release
pr_body: |
## Release
This pull request was created automatically according to the release cycle.
> [!WARNING]
> Only use `Merge Commit` to merge this pull request. Do not use `Rebase and Merge` or `Squash and Merge`.
+5
View File
@@ -46,6 +46,8 @@ node_modules
# Babel.js
lib/
# types/* once we have full typescript support, we can generate types from the typescript files
!types/tsconfig.json
# cache folder
.cache
@@ -59,3 +61,6 @@ lib/
# Redis Dump
dump.rdb
# AI agents
.claude
+2
View File
@@ -0,0 +1,2 @@
types/tests.ts
types/eslint.config.mjs
+1 -2
View File
@@ -1,2 +1 @@
10.14.2
20.15.0
+33 -13
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,11 +29,13 @@ 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)';
// eslint-disable-next-line no-console
console.log(`Running on branch: ${branch}`);
// Set changelog file
const changelogFile = `./changelogs/CHANGELOG_release.md`;
// eslint-disable-next-line no-console
console.log(`Changelog file output to: ${changelogFile}`);
// Load template file contents
@@ -38,9 +45,9 @@ async function config() {
branches: [
'release',
{ name: 'alpha', prerelease: true },
{ name: 'beta', prerelease: true },
// Long-Term-Support branches
{ name: 'release-6.x.x', range: '6.x.x', channel: '6.x.x' },
// { name: 'beta', prerelease: true },
// Long-Term-Support branch
{ name: 'release-8.x.x', range: '8.x.x', channel: '8.x.x' },
],
dryRun: false,
debug: true,
@@ -54,13 +61,13 @@ async function config() {
{ scope: 'no-release', release: false },
],
parserOpts: {
noteKeywords: [ 'BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING' ],
noteKeywords: ['BREAKING CHANGE'],
},
}],
['@semantic-release/release-notes-generator', {
preset: 'angular',
parserOpts: {
noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING']
noteKeywords: ['BREAKING CHANGE']
},
writerOpts: {
commitsSort: ['subject', 'scope'],
@@ -84,6 +91,17 @@ async function config() {
labels: ['type:ci'],
releasedLabels: ['state:released<%= nextRelease.channel ? `-\${nextRelease.channel}` : "" %>']
}],
// Back-merge module runs last because if it fails it should not impede the release process
[
"@saithodev/semantic-release-backmerge",
{
"backmergeBranches": [
// { from: 'beta', to: 'alpha' },
// { from: 'release', to: 'beta' },
{ from: 'release', to: 'alpha' },
]
}
],
],
};
@@ -92,15 +110,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 + ')';
+44
View File
@@ -0,0 +1,44 @@
# Parse Server 8 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 8 please refer to the [changelog](https://github.com/parse-community/parse-server/blob/alpha/CHANGELOG.md).
---
- [Email Verification](#email-verification)
- [Database Indexes](#database-indexes)
---
## Email Verification
In order to remove sensitive information (PII) from technical logs, the `Parse.User.username` field has been removed from the email verification process. This means the username will no longer be used and the already existing verification token, that is internal to Parse Server and associated with the user, will be used instead. This makes use of the fact that an expired verification token is not deleted from the database by Parse Server, despite being expired, and can therefore be used to identify a user.
This change affects how verification emails with expired tokens are handled. When opening a verification link that contains an expired token, the page that the user is redirected to will no longer provide the `username` as a URL query parameter. Instead, the URL query parameter `token` will be provided.
The request to re-send a verification email changed to sending a `POST` request to the endpoint `/resend_verification_email` with `token` in the body, instead of `username`. If you have customized the HTML pages for email verification either for the `PagesRouter` in `/public/` or the deprecated `PublicAPIRouter` in `/public_html/`, you need to adapt the form request in your custom pages. See the example pages in these aforementioned directories for how the forms must be set up.
> [!WARNING]
> An expired verification token is not automatically deleted from the database by Parse Server even though it has expired. If you have implemented a custom clean-up logic that removes expired tokens, this will break the form request to re-send a verification email as the expired token won't be found and cannot be associated with any user. In that case you'll have to implement your custom process to re-send a verification email.
> [!IMPORTANT]
> Parse Server does not keep a history of verification tokens but only stores the most recently generated verification token in the database. Every time Parse Server generates a new verification token, the currently stored token is replaced. If a user opens a link with an expired token, and that token has already been replaced in the database, Parse Server cannot associate the expired token with any user. In this case, another way has to be offered to the user to re-send a verification email. To mitigate this issue, set the Parse Server option `emailVerifyTokenReuseIfValid: true` and set `emailVerifyTokenValidityDuration` to a longer duration, which ensures that the currently stored verification token is not replaced too soon.
Related pull request:
- https://github.com/parse-community/parse-server/pull/8488
## Database Indexes
As part of the email verification and password reset improvements in Parse Server 8, the queries used for these operations have changed to use tokens instead of username/email fields. To ensure optimal query performance, Parse Server now automatically creates indexes on the following fields during server initialization:
- `_User._email_verify_token`: used for email verification queries
- `_User._perishable_token`: used for password reset queries
These indexes are created automatically when Parse Server starts, similar to how indexes for `username` and `email` fields are created. No manual intervention is required.
> [!WARNING]
> If you have a large existing user base, the index creation may take some time during the first server startup after upgrading to Parse Server 8. The server logs will indicate when index creation is complete or if any errors occur. If you have any concerns regarding a potential database performance impact during index creation, you could create these indexes manually in a controlled procedure before upgrading Parse Server.
Related pull request:
- https://github.com/parse-community/parse-server/pull/9893
-13
View File
@@ -15,19 +15,6 @@ Details:
- Purpose: official release
- Suitable environment: production
## ⚠️ [Beta Releases][log_beta]
> ### “Please try out, we’d love your feedback!”
These are releases that are pretty stable, but may have still some bugs to be fixed before official release.
Details:
- Stability: *pretty stable*
- NPM channel: `@beta`
- Branch: [beta][branch_beta]
- Purpose: feature maturation
- Suitable environment: development
## 🔥 [Alpha Releases][log_alpha]
> ### “If you are curious to see what's next!”
+100 -14
View File
@@ -21,8 +21,13 @@
- [Good to Know](#good-to-know)
- [Troubleshooting](#troubleshooting)
- [Please Do's](#please-dos)
- [TypeScript Tests](#typescript-tests)
- [Test against Postgres](#test-against-postgres)
- [Postgres with Docker](#postgres-with-docker)
- [Performance Testing](#performance-testing)
- [Adding Tests](#adding-tests)
- [Adding Benchmarks](#adding-benchmarks)
- [Benchmark Guidelines](#benchmark-guidelines)
- [Breaking Changes](#breaking-changes)
- [Deprecation Policy](#deprecation-policy)
- [Feature Considerations](#feature-considerations)
@@ -39,6 +44,7 @@
- [Reverting](#reverting)
- [Security Vulnerability](#security-vulnerability)
- [Local Testing](#local-testing)
- [Environment](#environment)
- [Merging](#merging-1)
- [Releasing](#releasing)
- [General Considerations](#general-considerations)
@@ -238,11 +244,24 @@ Once you have babel running in watch mode, you can start making changes to parse
* Mocks belong in the `spec/support` folder.
* Please consider if any changes to the [docs](http://docs.parseplatform.org) are needed or add additional sections in the case of an enhancement or feature.
#### TypeScript Tests
Type tests are located in [/types/tests.ts](/types/tests.ts) and are responsible for ensuring that the type generation for each class is behaving as expected. Types are generated by manually running the script `npm run build:types`. The generated types are `.d.ts` files located in [/types](/types) and must not be manually changed after generation.
> [!CAUTION]
> An exemption are type changes to `src/Options/index.js` which must be manually updated in `types/Options/index.d.ts`, as these types are not generated via a script.
When developing type definitions you can run `npm run watch:ts` in order to rebuild your changes automatically upon each save. Use `npm run test:types` in order to run types tests against generated `.d.ts` files.
### Test against Postgres
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:
@@ -258,16 +277,14 @@ If your pull request introduces a change that may affect the storage or retrieva
* If your feature is intended to work with MongoDB and PostgreSQL, you can include or exclude tests more granularly with:
- `it_only_mongodb_version('>=4.4')` // will test with any version of Postgres but only with version >=4.4 of MongoDB; accepts semver notation to specify a version range
- `it_exclude_mongodb_version('<4.4')` // will test with any version of Postgres and MongoDB, excluding version <4.4 of MongoDB; accepts semver notation to specify a version range
- `it_only_postgres_version('>=13')` // will test with any version of Mongo but only with version >=13 of Postgres; accepts semver notation to specify a version range
- `it_exclude_postgres_version('<13')` // will test with any version of Postgres and MongoDB, excluding version <13 of Postgres; accepts semver notation to specify a version range
#### 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:17-3.5-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:
@@ -275,7 +292,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:17-3.5-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
@@ -285,6 +302,58 @@ RUN chmod +x /docker-entrypoint-initdb.d/setup-dbs.sh
Note that the script above will ONLY be executed during initialization of the container with no data in the database, see the official [Postgres image](https://hub.docker.com/_/postgres) for details. If you want to use the script to run again be sure there is no data in the /var/lib/postgresql/data of the container.
### Performance Testing
Parse Server includes an automated performance benchmarking system that runs on every pull request to detect performance regressions and track improvements over time.
#### Adding Tests
You should consider adding performance benchmarks if your contribution:
- **Introduces a performance-critical feature**: Features that will be frequently used in production environments, such as new query operations, authentication methods, or data processing functions.
- **Modifies existing critical paths**: Changes to core functionality like object CRUD operations, query execution, user authentication, file operations, or Cloud Code execution.
- **Has potential performance impact**: Any change that affects database operations, network requests, data parsing, caching mechanisms, or algorithmic complexity.
- **Optimizes performance**: If your PR specifically aims to improve performance, adding benchmarks helps verify the improvement and prevents future regressions.
#### Adding Benchmarks
Performance benchmarks are located in [`benchmark/performance.js`](benchmark/performance.js). To add a new benchmark:
1. **Identify the operation to benchmark**: Determine the specific operation you want to measure (e.g., a new query type, a new API endpoint).
2. **Create a benchmark function**: Follow the existing patterns in `benchmark/performance.js`:
```javascript
async function benchmarkNewFeature() {
return measureOperation('Feature Name', async () => {
// Your operation to benchmark
const result = await someOperation();
}, ITERATIONS);
}
```
3. **Add to benchmark suite**: Register your benchmark in the `runBenchmarks()` function:
```javascript
console.error('Running New Feature benchmark...');
await cleanupDatabase();
results.push(await benchmarkNewFeature());
```
4. **Test locally**: Run the benchmarks locally to verify they work:
```bash
npm run benchmark:quick # Quick test with 10 iterations
npm run benchmark # Full test with 10,000 iterations
```
For new features where no baseline exists, the CI will establish new benchmarks that future PRs will be compared against.
#### Benchmark Guidelines
- **Keep benchmarks focused**: Each benchmark should test a single, well-defined operation.
- **Use realistic data**: Test with data that reflects real-world usage patterns.
- **Clean up between runs**: Use `cleanupDatabase()` to ensure consistent test conditions.
- **Consider iteration count**: Use fewer iterations for expensive operations (see `ITERATIONS` environment variable).
- **Document what you're testing**: Add clear comments explaining what the benchmark measures and why it's important.
## Breaking Changes
Breaking changes should be avoided whenever possible. For a breaking change to be accepted, the benefits of the change have to clearly outweigh the costs of developers having to adapt their deployments. If a breaking change is only cosmetic it will likely be rejected and preferred to become obsolete organically during the course of further development, unless it is required as part of a larger change. Breaking changes should follow the [Deprecation Policy](#deprecation-policy).
@@ -495,19 +564,36 @@ If the commit reverts a previous commit, use the prefix `revert:`, followed by t
#### 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:
Fixes for security 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 vulnerability 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)
- `npm run test` to test with MongoDB
- `npm run test:postgres:testonly` to test with Postgres
- `npm run madge:circular` to detect circular dependencies
- `npm run lint` to check lint compliance
- `npm run definitions` to update the Parse Server options definitions
> [!CAUTION]
> It is essential to run `npm run build` *after* switching to a different branch or making a commit and *before* running any tests. Otherwise the tests may run on the build from a different branch or on a build that does not reflect the most recent commits.
#### Environment
A reported vulnerability may have already been fixed since it was reported, either due to a targeted fix or as side-effect of other code changed. To verify that a vulnerability exists, tests need to be run in an environment that uses the latest commit of the development branch of Parse Server.
> [!NOTE]
> Do not use the latest alpha version for testing as it may be behind the latest commit of the development branch.
Vulnerability test must only be conducted in environments for which the tester can ensure that no unauthorized 3rd party has potentially access to. This is to ensure a vulnerability stays confidential and is not exposed prematurely to the public.
You must not test a vulnerability using any 3rd party APIs that provide Parse Server as a hosted service (SaaS) as this may expose the vulnerability to an unauthorized 3rd party and the effects of the vulnerability may cause issues on the provider's side.
> [!CAUTION]
> Utilizing a vulnerability in a third-party service, even for testing or development purposes, can result in legal repercussions. You are solely accountable for any damage arising from such actions and agree to indemnify Parse Platform against any liabilities or claims resulting from your actions.
#### 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.
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 vulnerability. 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.
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 hinting to a vulnerability or giving any details about the vulnerability, until the pull request has been successfully merged.
## Releasing
+14 -12
View File
@@ -2,18 +2,20 @@
The following is a list of deprecations, according to the [Deprecation Policy](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#deprecation-policy). After a feature becomes deprecated, and giving developers time to adapt to the change, the deprecated feature will eventually be removed, leading to a breaking change. Developer feedback during the deprecation period may postpone or even revoke the introduction of the breaking change.
| 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) | 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) | 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 | - |
| 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) | deprecated | - |
| 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) | deprecated | - |
| 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 | - |
| 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) | 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 | Encode `Parse.Object` in Cloud Function and remove option `encodeParseObjectInCloudFunction` | [#8634](https://github.com/parse-community/parse-server/issues/8634) | 6.2.0 (2023) | 9.0.0 (2026) | deprecated | - |
| DEPPS11 | Replace `PublicAPIRouter` with `PagesRouter` | [#7625](https://github.com/parse-community/parse-server/issues/7625) | 8.0.0 (2025) | 9.0.0 (2026) | deprecated | - |
| DEPPS12 | Database option `allowPublicExplain` will default to `true` | [#7519](https://github.com/parse-community/parse-server/issues/7519) | 8.5.0 (2025) | 9.0.0 (2026) | deprecated | - |
[i_deprecation]: ## "The version and date of the deprecation."
[i_removal]: ## "The version and date of the planned removal."
+7 -3
View File
@@ -1,9 +1,13 @@
############################################################
# Build stage
############################################################
FROM node:18-alpine AS build
FROM node:20.19.0-alpine3.20 AS build
RUN apk --no-cache add \
build-base \
git \
python3
RUN apk --no-cache add git
WORKDIR /tmp
# Copy package.json first to benefit from layer caching
@@ -24,7 +28,7 @@ RUN npm ci --omit=dev --ignore-scripts \
############################################################
# Release stage
############################################################
FROM node:18-alpine AS release
FROM node:20.19.0-alpine3.20 AS release
VOLUME /parse-server/cloud /parse-server/config
+44 -110
View File
@@ -2,19 +2,17 @@
---
[![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)
[![Build Status](https://github.com/parse-community/parse-server/actions/workflows/ci.yml/badge.svg?branch=alpha)](https://github.com/parse-community/parse-server/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Aalpha)
[![Build Status](https://github.com/parse-community/parse-server/actions/workflows/ci.yml/badge.svg?branch=release)](https://github.com/parse-community/parse-server/actions/workflows/ci.yml?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-14,_16,_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,_6-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com)
[![Postgres Version](https://img.shields.io/badge/postgresql-11,_12,_13,_14,_15-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org)
[![Node Version](https://img.shields.io/badge/nodejs-18,_20,_22,_24-green.svg?logo=node.js&style=flat)](https://nodejs.org)
[![MongoDB Version](https://img.shields.io/badge/mongodb-6,_7,_8-green.svg?logo=mongodb&style=flat)](https://www.mongodb.com)
[![Postgres Version](https://img.shields.io/badge/postgresql-13,_14,_15,_16,_17,_18-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)
[![npm alpha version](https://img.shields.io/npm/v/parse-server/alpha.svg)](https://www.npmjs.com/package/parse-server)
[![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)][open-collective-link]
@@ -49,7 +47,7 @@ A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who
- [PostgreSQL](#postgresql)
- [Locally](#locally)
- [Docker Container](#docker-container)
- [Saving an Object](#saving-an-object)
- [Saving and Querying Objects](#saving-and-querying-objects)
- [Connect an SDK](#connect-an-sdk)
- [Running Parse Server elsewhere](#running-parse-server-elsewhere)
- [Sample Application](#sample-application)
@@ -100,7 +98,7 @@ A big *thank you* 🙏 to our [sponsors](#sponsors) and [backers](#backers) who
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 main branches are [release][log_release] 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
@@ -127,36 +125,35 @@ Before you start make sure you have installed:
Parse Server is continuously tested with the most recent releases of Node.js to ensure compatibility. We follow the [Node.js Long Term Support plan](https://github.com/nodejs/Release) and only test against versions that are officially supported and have not reached their end-of-life date.
| Version | Latest Version | End-of-Life | Compatible |
|------------|----------------|-------------|------------|
| Node.js 14 | 14.19.1 | April 2023 | ✅ Yes |
| Node.js 16 | 16.14.2 | April 2024 | ✅ Yes |
| Node.js 18 | 18.12.1 | April 2025 | ✅ Yes |
| Node.js 19 | 19.3.0 | June 2023 | ✅ Yes |
| Version | Minimum Version | End-of-Life | Parse Server Support |
|------------|-----------------|-------------|----------------------|
| Node.js 18 | 18.20.4 | April 2025 | <= 8.x (2025) |
| Node.js 20 | 20.18.0 | April 2026 | <= 9.x (2026) |
| Node.js 22 | 22.12.0 | April 2027 | <= 10.x (2027) |
| Node.js 24 | 24.11.0 | April 2028 | <= 11.x (2028) |
#### 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 [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. We consider the end-of-life date of a MongoDB "rapid release" to be the same as its major version release.
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 | April 2023 | ✅ Yes |
| MongoDB 4.4 | 4.4.13 | February 2024 | ✅ Yes |
| MongoDB 5 | 5.3.2 | October 2024 | ✅ Yes |
| MongoDB 6 | 6.0.2 | July 2025 | ✅ Yes |
| Version | Minimum Version | End-of-Life | Parse Server Support |
|-----------|-----------------|-------------|----------------------|
| MongoDB 6 | 6.0.19 | July 2025 | <= 8.x (2025) |
| MongoDB 7 | 7.0.16 | August 2026 | <= 9.x (2026) |
| MongoDB 8 | 8.0.4 | TDB | <= 10.x (2027) |
#### 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 about 2 years before the official end-of-life date.
| Version | PostGIS Version | End-of-Life | Parse Server Support | Compatible |
|-------------|--------------------|---------------|----------------------|------------|
| Postgres 11 | 3.0, 3.1, 3.2, 3.3 | November 2023 | <= 5.x (2022) | ✅ Yes |
| Postgres 12 | 3.3 | November 2024 | <= 5.x (2022) | ✅ Yes |
| Postgres 13 | 3.3 | November 2025 | <= 6.x (2023) | ✅ Yes |
| Postgres 14 | 3.3 | November 2026 | <= 7.x (2024) | ✅ Yes |
| Postgres 15 | 3.3 | November 2027 | <= 8.x (2025) | ✅ Yes |
| Version | PostGIS Version | End-of-Life | Parse Server Support |
|-------------|-------------------------|---------------|----------------------|
| Postgres 13 | 3.1, 3.2, 3.3, 3.4, 3.5 | November 2025 | <= 6.x (2023) |
| Postgres 14 | 3.5 | November 2026 | <= 7.x (2024) |
| Postgres 15 | 3.3, 3.4, 3.5 | November 2027 | <= 8.x (2025) |
| Postgres 16 | 3.5 | November 2028 | <= 9.x (2026) |
| Postgres 17 | 3.5 | November 2029 | <= 10.x (2027) |
| Postgres 18 | 3.6 | November 2030 | <= 11.x (2028) |
### Locally
@@ -191,70 +188,9 @@ That's it! You are now running a standalone version of Parse Server on your mach
**Using a remote MongoDB?** Pass the `--databaseURI DATABASE_URI` parameter when starting `parse-server`. Learn more about configuring Parse Server [here](#configuration). For a full list of available options, run `parse-server --help`.
### Saving an Object
### Saving and Querying Objects
Now that you're running Parse Server, it is time to save your first object. We'll use the [REST API](http://docs.parseplatform.org/rest/guide), but you can easily do the same using any of the [Parse SDKs](http://parseplatform.org/#sdks). Run the following:
```bash
$ curl -X POST \
-H "X-Parse-Application-Id: APPLICATION_ID" \
-H "Content-Type: application/json" \
-d '{"score":1337,"playerName":"Sean Plott","cheatMode":false}' \
http://localhost:1337/parse/classes/GameScore
```
You should get a response similar to this:
```js
{
"objectId": "2ntvSpRGIK",
"createdAt": "2016-03-11T23:51:48.050Z"
}
```
You can now retrieve this object directly (make sure to replace `2ntvSpRGIK` with the actual `objectId` you received when the object was created):
```bash
$ curl -X GET \
-H "X-Parse-Application-Id: APPLICATION_ID" \
http://localhost:1337/parse/classes/GameScore/2ntvSpRGIK
```
```json
// Response
{
"objectId": "2ntvSpRGIK",
"score": 1337,
"playerName": "Sean Plott",
"cheatMode": false,
"updatedAt": "2016-03-11T23:51:48.050Z",
"createdAt": "2016-03-11T23:51:48.050Z"
}
```
Keeping tracks of individual object ids is not ideal, however. In most cases you will want to run a query over the collection, like so:
```bash
$ curl -X GET \
-H "X-Parse-Application-Id: APPLICATION_ID" \
http://localhost:1337/parse/classes/GameScore
```
```json
// The response will provide all the matching objects within the `results` array:
{
"results": [
{
"objectId": "2ntvSpRGIK",
"score": 1337,
"playerName": "Sean Plott",
"cheatMode": false,
"updatedAt": "2016-03-11T23:51:48.050Z",
"createdAt": "2016-03-11T23:51:48.050Z"
}
]
}
```
To learn more about using saving and querying objects on Parse Server, check out the [Parse documentation](http://docs.parseplatform.org).
Now that you're running Parse Server, it is time to save your first object. The easiest way is to use the [REST API](http://docs.parseplatform.org/rest/guide), but you can easily do the same using any of the [Parse SDKs](http://parseplatform.org/#sdks). To learn more check out the [documentation](http://docs.parseplatform.org).
### Connect an SDK
@@ -278,6 +214,7 @@ We have provided a basic [Node.js application](https://github.com/parse-communit
* [Back4app](https://www.back4app.com/docs/get-started/welcome)
* [Glitch](https://glitch.com/edit/#!/parse-server)
* [Flynn](https://flynn.io/blog/parse-apps-on-flynn)
* [Elestio](https://elest.io/open-source/parse)
### Parse Server + Express
@@ -308,7 +245,7 @@ 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).
For a full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations][server-options].
## Parse Server Health
@@ -335,7 +272,7 @@ The response looks like this:
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.
For the 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).
For the full list of available options, run `parse-server --help` or take a look at [Parse Server Configurations][server-options].
## Basic Options
@@ -369,7 +306,7 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
## 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.
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][server-options] for more details and a full list of available options.
```js
const server = ParseServer({
@@ -409,7 +346,7 @@ Email adapters contributed by the community:
## Password and Account Policy
Set a password and account policy that meets your security requirements. The following is an example configuration. See the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) for more details and a full list of available options.
Set a password and account policy that meets your security requirements. The following is an example configuration. See the [Parse Server Options][server-options] for more details and a full list of available options.
```js
const server = ParseServer({
@@ -439,8 +376,6 @@ const server = ParseServer({
## Custom Routes
**Caution, this is an experimental feature that may not be appropriate for production.**
Custom routes allow to build user flows with webpages, similar to the existing password reset and email verification features. Custom routes are defined with the `pages` option in the Parse Server configuration:
### Example
@@ -450,7 +385,7 @@ const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for custom routes
enableRouter: true,
customRoutes: [{
method: 'GET',
path: 'custom_route',
@@ -487,7 +422,7 @@ The following paths are already used by Parse Server's built-in features and are
| Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
|------------------------------|----------|-----------------|---------------|-----------------------|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
| `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. **Caution, this is an experimental feature that may not be appropriate for production.** |
| `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. |
| `pages.customRoutes` | yes | `Array` | `[]` | - | `PARSE_SERVER_PAGES_CUSTOM_ROUTES` | The custom routes. The routes are added in the order they are defined here, which has to be considered since requests traverse routes in an ordered manner. Custom routes are traversed after build-in routes such as password reset and email verification. |
| `pages.customRoutes.method` | | `String` | - | `GET`, `POST` | - | The HTTP method of the custom route. |
| `pages.customRoutes.path` | | `String` | - | `custom_page` | - | The path of the custom route. Note that the same path can used if the `method` is different, for example a path `custom_page` can have two routes, a `GET` and `POST` route, which will be invoked depending on the HTTP request method. |
@@ -610,8 +545,6 @@ Assuming the script above is named, `parse_idempotency_delete_expired_records.sh
### Pages
**Caution, this is an experimental feature that may not be appropriate for production.**
Custom pages as well as feature pages (e.g. password reset, email verification) can be localized with the `pages` option in the Parse Server configuration:
```js
@@ -619,7 +552,7 @@ const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableRouter: true,
enableLocalization: true,
}
}
@@ -667,7 +600,7 @@ const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableRouter: true,
enableLocalization: true,
customUrls: {
passwordReset: 'https://example.com/page.html'
@@ -724,7 +657,7 @@ const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableRouter: true,
enableLocalization: true,
localizationJsonPath: './private/localization.json',
localizationFallbackLocale: 'en'
@@ -749,7 +682,7 @@ const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableRouter: true,
placeholders: {
exampleKey: 'exampleValue'
}
@@ -763,7 +696,7 @@ const api = new ParseServer({
...otherOptions,
pages: {
enableRouter: true, // Enables the experimental feature; required for localization
enableRouter: true,
placeholders: async (params) => {
const value = await doSomething(params.locale);
return {
@@ -783,7 +716,7 @@ The following parameter and placeholder keys are reserved because they are used
| Parameter | Optional | Type | Default value | Example values | Environment variable | Description |
|-------------------------------------------------|----------|---------------------------------------|----------------------------------------|------------------------------------------------------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pages` | yes | `Object` | `undefined` | - | `PARSE_SERVER_PAGES` | The options for pages such as password reset and email verification. |
| `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. **Caution, this is an experimental feature that may not be appropriate for production.** |
| `pages.enableRouter` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_ROUTER` | Is `true` if the pages router should be enabled; this is required for any of the pages options to take effect. |
| `pages.enableLocalization` | yes | `Boolean` | `false` | - | `PARSE_SERVER_PAGES_ENABLE_LOCALIZATION` | Is true if pages should be localized; this has no effect on custom page redirects. |
| `pages.localizationJsonPath` | yes | `String` | `undefined` | `./private/translations.json` | `PARSE_SERVER_PAGES_LOCALIZATION_JSON_PATH` | The path to the JSON file for localization; the translations will be used to fill template placeholders according to the locale. |
| `pages.localizationFallbackLocale` | yes | `String` | `en` | `en`, `en-GB`, `default` | `PARSE_SERVER_PAGES_LOCALIZATION_FALLBACK_LOCALE` | The fallback locale for localization if no matching translation is provided for the given locale. This is only relevant when providing translation resources via JSON file. |
@@ -1209,3 +1142,4 @@ Support us with a monthly donation and help us continue our activities. [Become
[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
[server-options] http://parseplatform.org/parse-server/api/release/ParseServerOptions.html
+137
View File
@@ -0,0 +1,137 @@
/**
* MongoDB Latency Wrapper
*
* Utility to inject artificial latency into MongoDB operations for performance testing.
* This wrapper temporarily wraps MongoDB Collection methods to add delays before
* database operations execute.
*
* Usage:
* const { wrapMongoDBWithLatency } = require('./MongoLatencyWrapper');
*
* // Before initializing Parse Server
* const unwrap = wrapMongoDBWithLatency(10); // 10ms delay
*
* // ... run benchmarks ...
*
* // Cleanup when done
* unwrap();
*/
const { Collection } = require('mongodb');
// Store original methods for restoration
const originalMethods = new Map();
/**
* Wrap a Collection method to add artificial latency
* @param {string} methodName - Name of the method to wrap
* @param {number} latencyMs - Delay in milliseconds
*/
function wrapMethod(methodName, latencyMs) {
if (!originalMethods.has(methodName)) {
originalMethods.set(methodName, Collection.prototype[methodName]);
}
const originalMethod = originalMethods.get(methodName);
Collection.prototype[methodName] = function (...args) {
// For methods that return cursors (like find, aggregate), we need to delay the execution
// but still return a cursor-like object
const result = originalMethod.apply(this, args);
// Check if result has cursor methods (toArray, forEach, etc.)
if (result && typeof result.toArray === 'function') {
// Wrap cursor methods that actually execute the query
const originalToArray = result.toArray.bind(result);
result.toArray = function() {
// Wait for the original promise to settle, then delay the result
return originalToArray().then(
value => new Promise(resolve => setTimeout(() => resolve(value), latencyMs)),
error => new Promise((_, reject) => setTimeout(() => reject(error), latencyMs))
);
};
return result;
}
// For promise-returning methods, wrap the promise with delay
if (result && typeof result.then === 'function') {
// Wait for the original promise to settle, then delay the result
return result.then(
value => new Promise(resolve => setTimeout(() => resolve(value), latencyMs)),
error => new Promise((_, reject) => setTimeout(() => reject(error), latencyMs))
);
}
// For synchronous methods, just add delay
return new Promise((resolve) => {
setTimeout(() => {
resolve(result);
}, latencyMs);
});
};
}
/**
* Wrap MongoDB Collection methods with artificial latency
* @param {number} latencyMs - Delay in milliseconds to inject before each operation
* @returns {Function} unwrap - Function to restore original methods
*/
function wrapMongoDBWithLatency(latencyMs) {
if (typeof latencyMs !== 'number' || latencyMs < 0) {
throw new Error('latencyMs must be a non-negative number');
}
if (latencyMs === 0) {
// eslint-disable-next-line no-console
console.log('Latency is 0ms, skipping MongoDB wrapping');
return () => {}; // No-op unwrap function
}
// eslint-disable-next-line no-console
console.log(`Wrapping MongoDB operations with ${latencyMs}ms artificial latency`);
// List of MongoDB Collection methods to wrap
const methodsToWrap = [
'find',
'findOne',
'countDocuments',
'estimatedDocumentCount',
'distinct',
'aggregate',
'insertOne',
'insertMany',
'updateOne',
'updateMany',
'replaceOne',
'deleteOne',
'deleteMany',
'findOneAndUpdate',
'findOneAndReplace',
'findOneAndDelete',
'createIndex',
'createIndexes',
'dropIndex',
'dropIndexes',
'drop',
];
methodsToWrap.forEach(methodName => {
wrapMethod(methodName, latencyMs);
});
// Return unwrap function to restore original methods
return function unwrap() {
// eslint-disable-next-line no-console
console.log('Removing MongoDB latency wrapper, restoring original methods');
originalMethods.forEach((originalMethod, methodName) => {
Collection.prototype[methodName] = originalMethod;
});
originalMethods.clear();
};
}
module.exports = {
wrapMongoDBWithLatency,
};
+631
View File
@@ -0,0 +1,631 @@
/**
* Performance Benchmark Suite for Parse Server
*
* This suite measures the performance of critical Parse Server operations
* using the Node.js Performance API. Results are output in a format
* compatible with github-action-benchmark.
*
* Run with: npm run benchmark
*/
const core = require('@actions/core');
const Parse = require('parse/node');
const { performance } = require('node:perf_hooks');
const { MongoClient } = require('mongodb');
const { wrapMongoDBWithLatency } = require('./MongoLatencyWrapper');
// Configuration
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/parse_benchmark_test';
const SERVER_URL = 'http://localhost:1337/parse';
const APP_ID = 'benchmark-app-id';
const MASTER_KEY = 'benchmark-master-key';
const ITERATIONS = process.env.BENCHMARK_ITERATIONS ? parseInt(process.env.BENCHMARK_ITERATIONS, 10) : undefined;
const LOG_ITERATIONS = false;
// Parse Server instance
let parseServer;
let mongoClient;
// Logging helpers
const logInfo = message => core.info(message);
const logError = message => core.error(message);
/**
* Initialize Parse Server for benchmarking
*/
async function initializeParseServer() {
const express = require('express');
const { default: ParseServer } = require('../lib/index.js');
const app = express();
parseServer = new ParseServer({
databaseURI: MONGODB_URI,
appId: APP_ID,
masterKey: MASTER_KEY,
serverURL: SERVER_URL,
silent: true,
allowClientClassCreation: true,
logLevel: 'error', // Minimal logging for performance
verbose: false,
});
app.use('/parse', parseServer.app);
return new Promise((resolve, reject) => {
const server = app.listen(1337, (err) => {
if (err) {
reject(new Error(`Failed to start server: ${err.message}`));
return;
}
Parse.initialize(APP_ID);
Parse.masterKey = MASTER_KEY;
Parse.serverURL = SERVER_URL;
resolve(server);
});
server.on('error', (err) => {
reject(new Error(`Server error: ${err.message}`));
});
});
}
/**
* Clean up database between benchmarks
*/
async function cleanupDatabase() {
try {
if (!mongoClient) {
mongoClient = await MongoClient.connect(MONGODB_URI);
}
const db = mongoClient.db();
const collections = await db.listCollections().toArray();
for (const collection of collections) {
if (!collection.name.startsWith('system.')) {
await db.collection(collection.name).deleteMany({});
}
}
} catch (error) {
throw new Error(`Failed to cleanup database: ${error.message}`);
}
}
/**
* Reset Parse SDK to use the default server
*/
function resetParseServer() {
Parse.serverURL = SERVER_URL;
}
/**
* Measure average time for an async operation over multiple iterations.
* @param {Object} options Measurement options.
* @param {string} options.name Name of the operation being measured.
* @param {Function} options.operation Async function to measure.
* @param {number} options.iterations Number of iterations to run; choose a value that is high
* enough to create reliable benchmark metrics with low variance but low enough to keep test
* duration reasonable around <=10 seconds.
* @param {boolean} [options.skipWarmup=false] Skip warmup phase.
* @param {number} [options.dbLatency] Artificial DB latency in milliseconds to apply during
* this benchmark.
*/
async function measureOperation({ name, operation, iterations, skipWarmup = false, dbLatency }) {
// Override iterations if global ITERATIONS is set
iterations = ITERATIONS || iterations;
// Determine warmup count (20% of iterations)
const warmupCount = skipWarmup ? 0 : Math.floor(iterations * 0.2);
const times = [];
// Apply artificial latency if specified
let unwrapLatency = null;
if (dbLatency !== undefined && dbLatency > 0) {
logInfo(`Applying ${dbLatency}ms artificial DB latency for this benchmark`);
unwrapLatency = wrapMongoDBWithLatency(dbLatency);
}
try {
if (warmupCount > 0) {
logInfo(`Starting warmup phase of ${warmupCount} iterations...`);
const warmupStart = performance.now();
for (let i = 0; i < warmupCount; i++) {
await operation();
}
logInfo(`Warmup took: ${(performance.now() - warmupStart).toFixed(2)}ms`);
}
// Measurement phase
logInfo(`Starting measurement phase of ${iterations} iterations...`);
const progressInterval = Math.ceil(iterations / 10); // Log every 10%
const measurementStart = performance.now();
for (let i = 0; i < iterations; i++) {
const start = performance.now();
await operation();
const end = performance.now();
const duration = end - start;
times.push(duration);
// Log progress every 10% or individual iterations if LOG_ITERATIONS is enabled
if (LOG_ITERATIONS) {
logInfo(`Iteration ${i + 1}: ${duration.toFixed(2)}ms`);
} else if ((i + 1) % progressInterval === 0 || i + 1 === iterations) {
const progress = Math.round(((i + 1) / iterations) * 100);
logInfo(`Progress: ${progress}%`);
}
}
logInfo(`Measurement took: ${(performance.now() - measurementStart).toFixed(2)}ms`);
// Sort times for percentile calculations
times.sort((a, b) => a - b);
// Filter outliers using Interquartile Range (IQR) method
const q1Index = Math.floor(times.length * 0.25);
const q3Index = Math.floor(times.length * 0.75);
const q1 = times[q1Index];
const q3 = times[q3Index];
const iqr = q3 - q1;
const lowerBound = q1 - 1.5 * iqr;
const upperBound = q3 + 1.5 * iqr;
const filtered = times.filter(t => t >= lowerBound && t <= upperBound);
// Calculate statistics on filtered data
const median = filtered[Math.floor(filtered.length * 0.5)];
const p95 = filtered[Math.floor(filtered.length * 0.95)];
const p99 = filtered[Math.floor(filtered.length * 0.99)];
const min = filtered[0];
const max = filtered[filtered.length - 1];
return {
name,
value: median, // Use median (p50) as primary metric for stability in CI
unit: 'ms',
range: `${min.toFixed(2)} - ${max.toFixed(2)}`,
extra: `p95: ${p95.toFixed(2)}ms, p99: ${p99.toFixed(2)}ms, n=${filtered.length}/${times.length}`,
};
} finally {
// Remove latency wrapper if it was applied
if (unwrapLatency) {
unwrapLatency();
logInfo('Removed artificial DB latency');
}
}
}
/**
* Benchmark: Object Create
*/
async function benchmarkObjectCreate(name) {
let counter = 0;
return measureOperation({
name,
iterations: 1_000,
operation: async () => {
const TestObject = Parse.Object.extend('BenchmarkTest');
const obj = new TestObject();
obj.set('testField', `test-value-${counter++}`);
obj.set('number', counter);
obj.set('boolean', true);
await obj.save();
},
});
}
/**
* Benchmark: Object Read (by ID)
*/
async function benchmarkObjectRead(name) {
// Setup: Create test objects
const TestObject = Parse.Object.extend('BenchmarkTest');
const objects = [];
for (let i = 0; i < 1_000; i++) {
const obj = new TestObject();
obj.set('testField', `read-test-${i}`);
objects.push(obj);
}
await Parse.Object.saveAll(objects);
let counter = 0;
return measureOperation({
name,
iterations: 1_000,
operation: async () => {
const query = new Parse.Query('BenchmarkTest');
await query.get(objects[counter++ % objects.length].id);
},
});
}
/**
* Benchmark: Object Update
*/
async function benchmarkObjectUpdate(name) {
// Setup: Create test objects
const TestObject = Parse.Object.extend('BenchmarkTest');
const objects = [];
for (let i = 0; i < 1_000; i++) {
const obj = new TestObject();
obj.set('testField', `update-test-${i}`);
obj.set('counter', 0);
objects.push(obj);
}
await Parse.Object.saveAll(objects);
let counter = 0;
return measureOperation({
name,
iterations: 1_000,
operation: async () => {
const obj = objects[counter++ % objects.length];
obj.increment('counter');
obj.set('lastUpdated', new Date());
await obj.save();
},
});
}
/**
* Benchmark: Simple Query
*/
async function benchmarkSimpleQuery(name) {
// Setup: Create test data
const TestObject = Parse.Object.extend('BenchmarkTest');
const objects = [];
for (let i = 0; i < 100; i++) {
const obj = new TestObject();
obj.set('category', i % 10);
obj.set('value', i);
objects.push(obj);
}
await Parse.Object.saveAll(objects);
let counter = 0;
return measureOperation({
name,
iterations: 1_000,
operation: async () => {
const query = new Parse.Query('BenchmarkTest');
query.equalTo('category', counter++ % 10);
await query.find();
},
});
}
/**
* Benchmark: Batch Save (saveAll)
*/
async function benchmarkBatchSave(name) {
const BATCH_SIZE = 10;
return measureOperation({
name,
iterations: 1_000,
operation: async () => {
const TestObject = Parse.Object.extend('BenchmarkTest');
const objects = [];
for (let i = 0; i < BATCH_SIZE; i++) {
const obj = new TestObject();
obj.set('batchField', `batch-${i}`);
obj.set('timestamp', new Date());
objects.push(obj);
}
await Parse.Object.saveAll(objects);
},
});
}
/**
* Benchmark: User Signup
*/
async function benchmarkUserSignup(name) {
let counter = 0;
return measureOperation({
name,
iterations: 500,
operation: async () => {
counter++;
const user = new Parse.User();
user.set('username', `benchmark_user_${Date.now()}_${counter}`);
user.set('password', 'benchmark_password');
user.set('email', `benchmark${counter}@example.com`);
await user.signUp();
},
});
}
/**
* Benchmark: User Login
*/
async function benchmarkUserLogin(name) {
// Setup: Create test users
const users = [];
for (let i = 0; i < 10; i++) {
const user = new Parse.User();
user.set('username', `benchmark_login_user_${i}`);
user.set('password', 'benchmark_password');
user.set('email', `login${i}@example.com`);
await user.signUp();
users.push({ username: user.get('username'), password: 'benchmark_password' });
await Parse.User.logOut();
}
let counter = 0;
return measureOperation({
name,
iterations: 500,
operation: async () => {
const userCreds = users[counter++ % users.length];
await Parse.User.logIn(userCreds.username, userCreds.password);
await Parse.User.logOut();
},
});
}
/**
* Benchmark: Query with Include (Parallel Pointers)
* Tests the performance improvement when fetching multiple pointers at the same level.
*/
async function benchmarkQueryWithIncludeParallel(name) {
const PointerAClass = Parse.Object.extend('PointerA');
const PointerBClass = Parse.Object.extend('PointerB');
const PointerCClass = Parse.Object.extend('PointerC');
const RootClass = Parse.Object.extend('Root');
// Create pointer objects
const pointerAObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new PointerAClass();
obj.set('name', `pointerA-${i}`);
pointerAObjects.push(obj);
}
await Parse.Object.saveAll(pointerAObjects);
const pointerBObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new PointerBClass();
obj.set('name', `pointerB-${i}`);
pointerBObjects.push(obj);
}
await Parse.Object.saveAll(pointerBObjects);
const pointerCObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new PointerCClass();
obj.set('name', `pointerC-${i}`);
pointerCObjects.push(obj);
}
await Parse.Object.saveAll(pointerCObjects);
// Create Root objects with multiple pointers at the same level
const rootObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new RootClass();
obj.set('name', `root-${i}`);
obj.set('pointerA', pointerAObjects[i % pointerAObjects.length]);
obj.set('pointerB', pointerBObjects[i % pointerBObjects.length]);
obj.set('pointerC', pointerCObjects[i % pointerCObjects.length]);
rootObjects.push(obj);
}
await Parse.Object.saveAll(rootObjects);
return measureOperation({
name,
skipWarmup: true,
dbLatency: 100,
iterations: 100,
operation: async () => {
const query = new Parse.Query('Root');
// Include multiple pointers at the same level - should fetch in parallel
query.include(['pointerA', 'pointerB', 'pointerC']);
await query.find();
},
});
}
/**
* Benchmark: Query with Include (Nested Pointers with Parallel Leaf Nodes)
* Tests the PR's optimization for parallel fetching at each nested level.
* Pattern: p1.p2.p3, p1.p2.p4, p1.p2.p5
* After fetching p2, we know the objectIds and can fetch p3, p4, p5 in parallel.
*/
async function benchmarkQueryWithIncludeNested(name) {
const Level3AClass = Parse.Object.extend('Level3A');
const Level3BClass = Parse.Object.extend('Level3B');
const Level3CClass = Parse.Object.extend('Level3C');
const Level2Class = Parse.Object.extend('Level2');
const Level1Class = Parse.Object.extend('Level1');
const RootClass = Parse.Object.extend('Root');
// Create Level3 objects (leaf nodes)
const level3AObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new Level3AClass();
obj.set('name', `level3A-${i}`);
level3AObjects.push(obj);
}
await Parse.Object.saveAll(level3AObjects);
const level3BObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new Level3BClass();
obj.set('name', `level3B-${i}`);
level3BObjects.push(obj);
}
await Parse.Object.saveAll(level3BObjects);
const level3CObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new Level3CClass();
obj.set('name', `level3C-${i}`);
level3CObjects.push(obj);
}
await Parse.Object.saveAll(level3CObjects);
// Create Level2 objects pointing to multiple Level3 objects
const level2Objects = [];
for (let i = 0; i < 10; i++) {
const obj = new Level2Class();
obj.set('name', `level2-${i}`);
obj.set('level3A', level3AObjects[i % level3AObjects.length]);
obj.set('level3B', level3BObjects[i % level3BObjects.length]);
obj.set('level3C', level3CObjects[i % level3CObjects.length]);
level2Objects.push(obj);
}
await Parse.Object.saveAll(level2Objects);
// Create Level1 objects pointing to Level2
const level1Objects = [];
for (let i = 0; i < 10; i++) {
const obj = new Level1Class();
obj.set('name', `level1-${i}`);
obj.set('level2', level2Objects[i % level2Objects.length]);
level1Objects.push(obj);
}
await Parse.Object.saveAll(level1Objects);
// Create Root objects pointing to Level1
const rootObjects = [];
for (let i = 0; i < 10; i++) {
const obj = new RootClass();
obj.set('name', `root-${i}`);
obj.set('level1', level1Objects[i % level1Objects.length]);
rootObjects.push(obj);
}
await Parse.Object.saveAll(rootObjects);
return measureOperation({
name,
skipWarmup: true,
dbLatency: 100,
iterations: 100,
operation: async () => {
const query = new Parse.Query('Root');
// After fetching level1.level2, the PR should fetch level3A, level3B, level3C in parallel
query.include(['level1.level2.level3A', 'level1.level2.level3B', 'level1.level2.level3C']);
await query.find();
},
});
}
/**
* Benchmark: Object.save with nested data (denylist scanning)
*
* Measures create latency for objects with deeply nested structures containing
* multiple sibling objects at each level. This exercises the requestKeywordDenylist
* scanner (objectContainsKeyValue) which must traverse all keys and nested values.
*/
async function benchmarkObjectCreateNestedDenylist(name) {
let counter = 0;
return measureOperation({
name,
iterations: 1_000,
operation: async () => {
const TestObject = Parse.Object.extend('BenchmarkDenylist');
const obj = new TestObject();
const idx = counter++;
obj.set('nested', {
meta1: { info: { detail: `value-${idx}` } },
meta2: { info: { detail: `value-${idx}` } },
meta3: { info: { detail: `value-${idx}` } },
tags: ['a', 'b', 'c'],
config: {
setting1: { enabled: true, params: { x: 1 } },
setting2: { enabled: false, params: { y: 2 } },
},
});
await obj.save();
},
});
}
/**
* Run all benchmarks
*/
async function runBenchmarks() {
logInfo('Starting Parse Server Performance Benchmarks...');
let server;
try {
// Initialize Parse Server
logInfo('Initializing Parse Server...');
server = await initializeParseServer();
// Wait for server to be ready
await new Promise(resolve => setTimeout(resolve, 2000));
const results = [];
// Define all benchmarks to run
const benchmarks = [
{ name: 'Object.save (create)', fn: benchmarkObjectCreate },
{ name: 'Object.save (update)', fn: benchmarkObjectUpdate },
{ name: 'Object.saveAll (batch save)', fn: benchmarkBatchSave },
{ name: 'Query.get (by objectId)', fn: benchmarkObjectRead },
{ name: 'Query.find (simple query)', fn: benchmarkSimpleQuery },
{ name: 'User.signUp', fn: benchmarkUserSignup },
{ name: 'User.login', fn: benchmarkUserLogin },
{ name: 'Query.include (parallel pointers)', fn: benchmarkQueryWithIncludeParallel },
{ name: 'Query.include (nested pointers)', fn: benchmarkQueryWithIncludeNested },
{ name: 'Object.save (nested data, denylist scan)', fn: benchmarkObjectCreateNestedDenylist },
];
// Run each benchmark with database cleanup
for (const benchmark of benchmarks) {
logInfo(`\nRunning benchmark '${benchmark.name}'...`);
resetParseServer();
await cleanupDatabase();
results.push(await benchmark.fn(benchmark.name));
}
// Output results in github-action-benchmark format (stdout)
logInfo(JSON.stringify(results, null, 2));
// Output summary to stderr for visibility
logInfo('Benchmarks completed successfully!');
logInfo('Summary:');
results.forEach(result => {
logInfo(` ${result.name}: ${result.value.toFixed(2)} ${result.unit} (${result.extra})`);
});
} catch (error) {
logError('Error running benchmarks:', error);
process.exit(1);
} finally {
// Cleanup
if (mongoClient) {
await mongoClient.close();
}
if (server) {
server.close();
}
// Give some time for cleanup
setTimeout(() => process.exit(0), 1000);
}
}
// Run benchmarks if executed directly
if (require.main === module) {
runBenchmarks();
}
module.exports = { runBenchmarks };
File diff suppressed because it is too large Load Diff
+130
View File
@@ -1,3 +1,133 @@
# [7.4.0-beta.1](https://github.com/parse-community/parse-server/compare/7.3.0...7.4.0-beta.1) (2024-12-23)
### Bug Fixes
* `Parse.Query.distinct` fails due to invalid aggregate stage 'hint' ([#9295](https://github.com/parse-community/parse-server/issues/9295)) ([5f66c6a](https://github.com/parse-community/parse-server/commit/5f66c6a075cbe1cdaf9d1b108ee65af8ae596b89))
* Security upgrade cross-spawn from 7.0.3 to 7.0.6 ([#9444](https://github.com/parse-community/parse-server/issues/9444)) ([3d034e0](https://github.com/parse-community/parse-server/commit/3d034e0a993e3e5bd9bb96a7e382bb3464f1eb68))
* Security upgrade fast-xml-parser from 4.4.0 to 4.4.1 ([#9262](https://github.com/parse-community/parse-server/issues/9262)) ([992d39d](https://github.com/parse-community/parse-server/commit/992d39d508f230c774dcb764d1d907ec8887e6c5))
* Security upgrade node from 20.14.0-alpine3.20 to 20.17.0-alpine3.20 ([#9300](https://github.com/parse-community/parse-server/issues/9300)) ([15bb17d](https://github.com/parse-community/parse-server/commit/15bb17d87153bf0d38f08fe4c720da29a204b36b))
### Features
* Add support for MongoDB 8 ([#9269](https://github.com/parse-community/parse-server/issues/9269)) ([4756c66](https://github.com/parse-community/parse-server/commit/4756c66cd9f55afa1621d1a3f6fa850ed605cb53))
* Add support for PostGIS 3.5 ([#9354](https://github.com/parse-community/parse-server/issues/9354)) ([8ea3538](https://github.com/parse-community/parse-server/commit/8ea35382db3436d54ab59bd30706705564b0985c))
* Add support for Postgres 17 ([#9324](https://github.com/parse-community/parse-server/issues/9324)) ([fa2ee31](https://github.com/parse-community/parse-server/commit/fa2ee3196e4319a142b3838bb947c98dcba5d5cb))
* Upgrade @parse/push-adapter from 6.7.1 to 6.8.0 ([#9489](https://github.com/parse-community/parse-server/issues/9489)) ([286aa66](https://github.com/parse-community/parse-server/commit/286aa664ac8830d36c3e70d2316917d15f0b6df5))
# [7.3.0-beta.1](https://github.com/parse-community/parse-server/compare/7.2.0...7.3.0-beta.1) (2024-10-03)
### Bug Fixes
* Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) ([#9317](https://github.com/parse-community/parse-server/issues/9317)) ([13ee52f](https://github.com/parse-community/parse-server/commit/13ee52f0d19ef3a3524b3d79aea100e587eb3cfc))
* Parse Server `databaseOptions` nested keys incorrectly identified as invalid ([#9213](https://github.com/parse-community/parse-server/issues/9213)) ([77206d8](https://github.com/parse-community/parse-server/commit/77206d804443cfc1618c24f8961bd677de9920c0))
* Parse Server installation fails due to post install script incorrectly parsing required min. Node version ([#9216](https://github.com/parse-community/parse-server/issues/9216)) ([0fa82a5](https://github.com/parse-community/parse-server/commit/0fa82a54fe38ec14e8054339285d3db71a8624c8))
* Parse Server option `maxLogFiles` doesn't recognize day duration literals such as `1d` to mean 1 day ([#9215](https://github.com/parse-community/parse-server/issues/9215)) ([0319cee](https://github.com/parse-community/parse-server/commit/0319cee2dbf65e90bad377af1ed14ea25c595bf5))
* Security upgrade path-to-regexp from 6.2.1 to 6.3.0 ([#9314](https://github.com/parse-community/parse-server/issues/9314)) ([8b7fe69](https://github.com/parse-community/parse-server/commit/8b7fe699c1c376ecd8cc1c97cce8e704ee41f28a))
### Features
* Add atomic operations for Cloud Config parameters ([#9219](https://github.com/parse-community/parse-server/issues/9219)) ([35cadf9](https://github.com/parse-community/parse-server/commit/35cadf9b8324879fb7309ba5d7ea46f2c722d614))
* Add Cloud Code triggers `Parse.Cloud.beforeSave` and `Parse.Cloud.afterSave` for Parse Config ([#9232](https://github.com/parse-community/parse-server/issues/9232)) ([90a1e4a](https://github.com/parse-community/parse-server/commit/90a1e4a200423d644efb3f0ba2fba4b99f5cf954))
* Add Node 22 support ([#9187](https://github.com/parse-community/parse-server/issues/9187)) ([7778471](https://github.com/parse-community/parse-server/commit/7778471999c7e42236ce404229660d80ecc2acd6))
* Add support for asynchronous invocation of `FilesAdapter.getFileLocation` ([#9271](https://github.com/parse-community/parse-server/issues/9271)) ([1a2da40](https://github.com/parse-community/parse-server/commit/1a2da4055abe831b3017172fb75e16d7a8093873))
# [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)
+617 -24
View File
@@ -1,86 +1,679 @@
## [6.5.11](https://github.com/parse-community/parse-server/compare/6.5.10...6.5.11) (2024-10-23)
## [8.6.50](https://github.com/parse-community/parse-server/compare/8.6.49...8.6.50) (2026-03-17)
### Bug Fixes
* Security upgrade to path-to-regexp 6.2.2 ([#9365](https://github.com/parse-community/parse-server/issues/9365)) ([dfbafa7](https://github.com/parse-community/parse-server/commit/dfbafa702507da0d20667eabe8fdc835ca30c8e8))
* Protected fields leak via LiveQuery afterEvent trigger ([GHSA-5hmj-jcgp-6hff](https://github.com/parse-community/parse-server/security/advisories/GHSA-5hmj-jcgp-6hff)) ([#10233](https://github.com/parse-community/parse-server/issues/10233)) ([743324e](https://github.com/parse-community/parse-server/commit/743324e71fa2a6693bea78c4589cf2211b210eb6))
## [6.5.10](https://github.com/parse-community/parse-server/compare/6.5.9...6.5.10) (2024-10-12)
## [8.6.49](https://github.com/parse-community/parse-server/compare/8.6.48...8.6.49) (2026-03-16)
### Bug Fixes
* Security upgrade express from 4.21.0 to 4.21.1 ([#9339](https://github.com/parse-community/parse-server/issues/9339)) ([97627ee](https://github.com/parse-community/parse-server/commit/97627ee450f5abe04c92609f4ae2e63c49060d6a))
* Empty authData bypasses credential requirement on signup ([GHSA-wjqw-r9x4-j59v](https://github.com/parse-community/parse-server/security/advisories/GHSA-wjqw-r9x4-j59v)) ([#10220](https://github.com/parse-community/parse-server/issues/10220)) ([b62336b](https://github.com/parse-community/parse-server/commit/b62336be06d06e3e9fbf3365354363e381603f58))
## [6.5.9](https://github.com/parse-community/parse-server/compare/6.5.8...6.5.9) (2024-10-03)
## [8.6.48](https://github.com/parse-community/parse-server/compare/8.6.47...8.6.48) (2026-03-16)
### Bug Fixes
* Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) ([#9318](https://github.com/parse-community/parse-server/issues/9318)) ([1bfbccf](https://github.com/parse-community/parse-server/commit/1bfbccf9ee7ea77533b2b2aa7c4c69f3bd35e66f))
* Password reset token single-use bypass via concurrent requests ([GHSA-r3xq-68wh-gwvh](https://github.com/parse-community/parse-server/security/advisories/GHSA-r3xq-68wh-gwvh)) ([#10217](https://github.com/parse-community/parse-server/issues/10217)) ([83b4de0](https://github.com/parse-community/parse-server/commit/83b4de0b7ce722fac0ecbb5fe815e3da8fb6b8a0))
## [6.5.8](https://github.com/parse-community/parse-server/compare/6.5.7...6.5.8) (2024-09-12)
## [8.6.47](https://github.com/parse-community/parse-server/compare/8.6.46...8.6.47) (2026-03-15)
### Bug Fixes
* Various vulnerabilities related to cross-site scripting ([#9310](https://github.com/parse-community/parse-server/issues/9310)) ([d5290d4](https://github.com/parse-community/parse-server/commit/d5290d46e5ff9237970ae1ac2d2df4051cbf53e5))
* Cloud function dispatch crashes server via prototype chain traversal ([GHSA-4263-jgmp-7pf4](https://github.com/parse-community/parse-server/security/advisories/GHSA-4263-jgmp-7pf4)) ([#10211](https://github.com/parse-community/parse-server/issues/10211)) ([8d8c760](https://github.com/parse-community/parse-server/commit/8d8c7604790f931531ac31bd88c98eb3d995b9c5))
## [6.5.7](https://github.com/parse-community/parse-server/compare/6.5.6...6.5.7) (2024-06-30)
## [8.6.46](https://github.com/parse-community/parse-server/compare/8.6.45...8.6.46) (2026-03-15)
### 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) ([#9168](https://github.com/parse-community/parse-server/issues/9168)) ([f332d54](https://github.com/parse-community/parse-server/commit/f332d54577608c5ad927255e06d8c694e2e0ff5b))
* Revert accidental breaking default values for query complexity limits ([#10206](https://github.com/parse-community/parse-server/issues/10206)) ([a3a57c1](https://github.com/parse-community/parse-server/commit/a3a57c15077d0c9c902fd444de986915b942ab2f))
## [6.5.6](https://github.com/parse-community/parse-server/compare/6.5.5...6.5.6) (2024-05-16)
## [8.6.45](https://github.com/parse-community/parse-server/compare/8.6.44...8.6.45) (2026-03-15)
### Bug Fixes
* Facebook Limited Login not workind due to incorrect domain in JWT validation ([#9120](https://github.com/parse-community/parse-server/issues/9120)) ([0e92f76](https://github.com/parse-community/parse-server/commit/0e92f765e43d1e39285c5958d60cfd7fb76a3c90))
* Server crash via deeply nested query condition operators ([GHSA-9xp9-j92r-p88v](https://github.com/parse-community/parse-server/security/advisories/GHSA-9xp9-j92r-p88v)) ([#10203](https://github.com/parse-community/parse-server/issues/10203)) ([433fa8f](https://github.com/parse-community/parse-server/commit/433fa8fb19f813966871da8be874e1197a29b10b))
## [6.5.5](https://github.com/parse-community/parse-server/compare/6.5.4...6.5.5) (2024-03-19)
## [8.6.44](https://github.com/parse-community/parse-server/compare/8.6.43...8.6.44) (2026-03-14)
### 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) ([#9023](https://github.com/parse-community/parse-server/issues/9023)) ([5ae6d6a](https://github.com/parse-community/parse-server/commit/5ae6d6a36d75c4511029f0ba5673ae4b2999179b))
* Schema poisoning via prototype pollution in deep copy ([GHSA-9ccr-fpp6-78qf](https://github.com/parse-community/parse-server/security/advisories/GHSA-9ccr-fpp6-78qf)) ([#10201](https://github.com/parse-community/parse-server/issues/10201)) ([6aec8ea](https://github.com/parse-community/parse-server/commit/6aec8ea9e17375930e55406d0c62a429505924cc))
## [6.5.4](https://github.com/parse-community/parse-server/compare/6.5.3...6.5.4) (2024-03-16)
## [8.6.43](https://github.com/parse-community/parse-server/compare/8.6.42...8.6.43) (2026-03-14)
### Bug Fixes
* Server crashes when receiving an array of `Parse.Pointer` in the request body ([#9012](https://github.com/parse-community/parse-server/issues/9012)) ([8ff444d](https://github.com/parse-community/parse-server/commit/8ff444d42ef51bfe6808c4c3a5fe666bfe302ebe))
* LiveQuery subscription with invalid regular expression crashes server ([GHSA-827p-g5x5-h86c](https://github.com/parse-community/parse-server/security/advisories/GHSA-827p-g5x5-h86c)) ([#10199](https://github.com/parse-community/parse-server/issues/10199)) ([522f008](https://github.com/parse-community/parse-server/commit/522f008f64f6a4ae3c0b9a299ee6a53947a9c1ea))
## [6.5.3](https://github.com/parse-community/parse-server/compare/6.5.2...6.5.3) (2024-03-16)
## [8.6.42](https://github.com/parse-community/parse-server/compare/8.6.41...8.6.42) (2026-03-13)
### Bug Fixes
* Security upgrade follow-redirects from 1.15.5 to 1.15.6 ([#9019](https://github.com/parse-community/parse-server/issues/9019)) ([422958e](https://github.com/parse-community/parse-server/commit/422958e246da6f13011776c8dde028a00fb821cb))
* Session creation endpoint allows overwriting server-generated session fields ([GHSA-5v7g-9h8f-8pgg](https://github.com/parse-community/parse-server/security/advisories/GHSA-5v7g-9h8f-8pgg)) ([#10196](https://github.com/parse-community/parse-server/issues/10196)) ([2021b27](https://github.com/parse-community/parse-server/commit/2021b277e1ff1131cf79eb37bba07cc5fba872c7))
## [6.5.2](https://github.com/parse-community/parse-server/compare/6.5.1...6.5.2) (2024-03-02)
## [8.6.41](https://github.com/parse-community/parse-server/compare/8.6.40...8.6.41) (2026-03-13)
### Bug Fixes
* Security upgrade @parse/push-adapter from 5.1.0 to 5.1.1 ([#8975](https://github.com/parse-community/parse-server/issues/8975)) ([0fa0aab](https://github.com/parse-community/parse-server/commit/0fa0aabefe6bc9d356ee70be78dafc5fa22d4e17))
* Stored XSS filter bypass via Content-Type MIME parameter and missing XML extension blocklist entries ([GHSA-42ph-pf9q-cr72](https://github.com/parse-community/parse-server/security/advisories/GHSA-42ph-pf9q-cr72)) ([#10192](https://github.com/parse-community/parse-server/issues/10192)) ([c7599c5](https://github.com/parse-community/parse-server/commit/c7599c577a02b97eb5e76d4e20517b0283ae73c8))
## [6.5.1](https://github.com/parse-community/parse-server/compare/6.5.0...6.5.1) (2024-03-02)
## [8.6.40](https://github.com/parse-community/parse-server/compare/8.6.39...8.6.40) (2026-03-12)
### Bug Fixes
* Security upgrade @parse/push-adapter from 5.0.2 to 5.1.0 ([#8972](https://github.com/parse-community/parse-server/issues/8972)) ([bba24dd](https://github.com/parse-community/parse-server/commit/bba24dd8279ebb8e4084a5f00fbe3ab9fe6c01b4))
* GraphQL WebSocket endpoint bypasses security middleware ([GHSA-p2x3-8689-cwpg](https://github.com/parse-community/parse-server/security/advisories/GHSA-p2x3-8689-cwpg)) ([#10190](https://github.com/parse-community/parse-server/issues/10190)) ([21330d1](https://github.com/parse-community/parse-server/commit/21330d146c68b57a930a58b8a8cd9fbf09436cf3))
# [6.5.0](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0) (2024-03-01)
## [8.6.39](https://github.com/parse-community/parse-server/compare/8.6.38...8.6.39) (2026-03-11)
### 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 ([#8960](https://github.com/parse-community/parse-server/issues/8960)) ([a6e6549](https://github.com/parse-community/parse-server/commit/a6e654943536932904a69b51e513507fcf90a504))
* OAuth2 adapter app ID validation sends wrong token to introspection endpoint ([GHSA-69xg-f649-w5g2](https://github.com/parse-community/parse-server/security/advisories/GHSA-69xg-f649-w5g2)) ([#10188](https://github.com/parse-community/parse-server/issues/10188)) ([fd6f6a6](https://github.com/parse-community/parse-server/commit/fd6f6a6ea9df631a63702d24496046ecccc610d6))
## [8.6.38](https://github.com/parse-community/parse-server/compare/8.6.37...8.6.38) (2026-03-11)
### Bug Fixes
* Account takeover via operator injection in authentication data identifier ([GHSA-5fw2-8jcv-xh87](https://github.com/parse-community/parse-server/security/advisories/GHSA-5fw2-8jcv-xh87)) ([#10186](https://github.com/parse-community/parse-server/issues/10186)) ([93425df](https://github.com/parse-community/parse-server/commit/93425df2bc9368eab89644c93fa9ef481c043e3a))
## [8.6.37](https://github.com/parse-community/parse-server/compare/8.6.36...8.6.37) (2026-03-11)
### Bug Fixes
* OAuth2 adapter shares mutable state across providers via singleton instance ([GHSA-2cjm-2gwv-m892](https://github.com/parse-community/parse-server/security/advisories/GHSA-2cjm-2gwv-m892)) ([#10184](https://github.com/parse-community/parse-server/issues/10184)) ([6afa431](https://github.com/parse-community/parse-server/commit/6afa4315ea691d8fe36ed39f00fb50fd8affb691))
## [8.6.36](https://github.com/parse-community/parse-server/compare/8.6.35...8.6.36) (2026-03-11)
### Bug Fixes
* SQL injection via query field name when using PostgreSQL ([GHSA-c442-97qw-j6c6](https://github.com/parse-community/parse-server/security/advisories/GHSA-c442-97qw-j6c6)) ([#10182](https://github.com/parse-community/parse-server/issues/10182)) ([0b0398b](https://github.com/parse-community/parse-server/commit/0b0398bd23cb243c59c13c94866454668064c013))
## [8.6.35](https://github.com/parse-community/parse-server/compare/8.6.34...8.6.35) (2026-03-10)
### Bug Fixes
* Protected fields bypass via LiveQuery subscription WHERE clause ([GHSA-j7mm-f4rv-6q6q](https://github.com/parse-community/parse-server/security/advisories/GHSA-j7mm-f4rv-6q6q)) ([#10176](https://github.com/parse-community/parse-server/issues/10176)) ([dfc7e69](https://github.com/parse-community/parse-server/commit/dfc7e69b95c719589d267f50935d8660e2201a8c))
## [8.6.34](https://github.com/parse-community/parse-server/compare/8.6.33...8.6.34) (2026-03-10)
### Bug Fixes
* User enumeration via email verification endpoint ([GHSA-w54v-hf9p-8856](https://github.com/parse-community/parse-server/security/advisories/GHSA-w54v-hf9p-8856)) ([#10173](https://github.com/parse-community/parse-server/issues/10173)) ([d3defb8](https://github.com/parse-community/parse-server/commit/d3defb887d802aaef12600a1f0c9b729ea06eff9))
## [8.6.33](https://github.com/parse-community/parse-server/compare/8.6.32...8.6.33) (2026-03-10)
### Bug Fixes
* MFA recovery codes not consumed after use ([GHSA-4hf6-3x24-c9m8](https://github.com/parse-community/parse-server/security/advisories/GHSA-4hf6-3x24-c9m8)) ([#10171](https://github.com/parse-community/parse-server/issues/10171)) ([a00c4fa](https://github.com/parse-community/parse-server/commit/a00c4fa24ff059081d2617dd435f8ee3de215000))
## [8.6.32](https://github.com/parse-community/parse-server/compare/8.6.31...8.6.32) (2026-03-10)
### Bug Fixes
* Protected fields bypass via dot-notation in query and sort ([GHSA-r2m8-pxm9-9c4g](https://github.com/parse-community/parse-server/security/advisories/GHSA-r2m8-pxm9-9c4g)) ([#10168](https://github.com/parse-community/parse-server/issues/10168)) ([1787db3](https://github.com/parse-community/parse-server/commit/1787db3244acca5ced180eb9814e1cfad364d826))
## [8.6.31](https://github.com/parse-community/parse-server/compare/8.6.30...8.6.31) (2026-03-10)
### Bug Fixes
* SQL Injection via dot-notation sub-key name in `Increment` operation on PostgreSQL ([GHSA-gqpp-xgvh-9h7h](https://github.com/parse-community/parse-server/security/advisories/GHSA-gqpp-xgvh-9h7h)) ([#10166](https://github.com/parse-community/parse-server/issues/10166)) ([aa0de68](https://github.com/parse-community/parse-server/commit/aa0de68d20a23338c70db54f6c54f6028d263de1))
## [8.6.30](https://github.com/parse-community/parse-server/compare/8.6.29...8.6.30) (2026-03-09)
### Bug Fixes
* Stored XSS via file upload of HTML-renderable file types ([GHSA-v5hf-f4c3-m5rv](https://github.com/parse-community/parse-server/security/advisories/GHSA-v5hf-f4c3-m5rv)) ([#10164](https://github.com/parse-community/parse-server/issues/10164)) ([90936f9](https://github.com/parse-community/parse-server/commit/90936f9ca2d6d4a886b5549a8cdfabda98fcc168))
## [8.6.29](https://github.com/parse-community/parse-server/compare/8.6.28...8.6.29) (2026-03-09)
### Bug Fixes
* SQL injection via `Increment` operation on nested object field in PostgreSQL ([GHSA-q3vj-96h2-gwvg](https://github.com/parse-community/parse-server/security/advisories/GHSA-q3vj-96h2-gwvg)) ([#10163](https://github.com/parse-community/parse-server/issues/10163)) ([c92022f](https://github.com/parse-community/parse-server/commit/c92022f1ff12b119d7a6a807426925ce7d52e5ab))
## [8.6.28](https://github.com/parse-community/parse-server/compare/8.6.27...8.6.28) (2026-03-09)
### Bug Fixes
* SQL injection via dot-notation field name in PostgreSQL ([GHSA-qpr4-jrj4-6f27](https://github.com/parse-community/parse-server/security/advisories/GHSA-qpr4-jrj4-6f27)) ([#10160](https://github.com/parse-community/parse-server/issues/10160)) ([83f38fa](https://github.com/parse-community/parse-server/commit/83f38faab25d89e7bbe7c5c2087c5ee616479975))
## [8.6.27](https://github.com/parse-community/parse-server/compare/8.6.26...8.6.27) (2026-03-09)
### Bug Fixes
* LiveQuery `regexTimeout` default value not applied ([#10157](https://github.com/parse-community/parse-server/issues/10157)) ([94c4f52](https://github.com/parse-community/parse-server/commit/94c4f523e02be6d82f006cbacb18bec5a1de7f2e))
## [8.6.26](https://github.com/parse-community/parse-server/compare/8.6.25...8.6.26) (2026-03-09)
### Bug Fixes
* LDAP injection via unsanitized user input in DN and group filter construction ([GHSA-7m6r-fhh7-r47c](https://github.com/parse-community/parse-server/security/advisories/GHSA-7m6r-fhh7-r47c)) ([#10153](https://github.com/parse-community/parse-server/issues/10153)) ([2370611](https://github.com/parse-community/parse-server/commit/23706117220a7489558683f72e8fdc0983cf8dfc))
## [8.6.25](https://github.com/parse-community/parse-server/compare/8.6.24...8.6.25) (2026-03-09)
### Bug Fixes
* Classes `_GraphQLConfig` and `_Audience` master key bypass via generic class routes ([GHSA-7xg7-rqf6-pw6c](https://github.com/parse-community/parse-server/security/advisories/GHSA-7xg7-rqf6-pw6c)) ([#10152](https://github.com/parse-community/parse-server/issues/10152)) ([94aa653](https://github.com/parse-community/parse-server/commit/94aa65318c6a4b8d7b8f0b98c96d52e36d33dc9a))
## [8.6.24](https://github.com/parse-community/parse-server/compare/8.6.23...8.6.24) (2026-03-09)
### Bug Fixes
* Concurrent signup with same authentication creates duplicate users ([#10150](https://github.com/parse-community/parse-server/issues/10150)) ([fac8f33](https://github.com/parse-community/parse-server/commit/fac8f338ecdfeffcaed21d7e0729e2cf1ea9947d))
## [8.6.23](https://github.com/parse-community/parse-server/compare/8.6.22...8.6.23) (2026-03-08)
### Bug Fixes
* Rate limit bypass via batch request endpoint ([GHSA-775h-3xrc-c228](https://github.com/parse-community/parse-server/security/advisories/GHSA-775h-3xrc-c228)) ([#10148](https://github.com/parse-community/parse-server/issues/10148)) ([48b94ae](https://github.com/parse-community/parse-server/commit/48b94aed12006b5f1e501c0de8284a9541e60b1b))
## [8.6.22](https://github.com/parse-community/parse-server/compare/8.6.21...8.6.22) (2026-03-08)
### Bug Fixes
* Parse Server OAuth2 authentication adapter account takeover via identity spoofing ([GHSA-fr88-w35c-r596](https://github.com/parse-community/parse-server/security/advisories/GHSA-fr88-w35c-r596)) ([#10146](https://github.com/parse-community/parse-server/issues/10146)) ([238110b](https://github.com/parse-community/parse-server/commit/238110b5f63f47d9ef128bbd5d37795a85f31891))
## [8.6.21](https://github.com/parse-community/parse-server/compare/8.6.20...8.6.21) (2026-03-08)
### Bug Fixes
* Parse Server session token exfiltration via `redirectClassNameForKey` query parameter ([GHSA-6r2j-cxgf-495f](https://github.com/parse-community/parse-server/security/advisories/GHSA-6r2j-cxgf-495f)) ([#10144](https://github.com/parse-community/parse-server/issues/10144)) ([721abe8](https://github.com/parse-community/parse-server/commit/721abe8b7c76a3143936936a720d3782547d4d9c))
## [8.6.20](https://github.com/parse-community/parse-server/compare/8.6.19...8.6.20) (2026-03-08)
### Bug Fixes
* Parse Server role escalation and CLP bypass via direct `_Join table write ([GHSA-5f92-jrq3-28rc](https://github.com/parse-community/parse-server/security/advisories/GHSA-5f92-jrq3-28rc)) ([#10142](https://github.com/parse-community/parse-server/issues/10142)) ([1c58ef7](https://github.com/parse-community/parse-server/commit/1c58ef787894dcb67623c0fb889820ee1d2ddf1b))
## [8.6.19](https://github.com/parse-community/parse-server/compare/8.6.18...8.6.19) (2026-03-08)
### Bug Fixes
* Protected fields bypass via logical query operators ([GHSA-72hp-qff8-4pvv](https://github.com/parse-community/parse-server/security/advisories/GHSA-72hp-qff8-4pvv)) ([#10139](https://github.com/parse-community/parse-server/issues/10139)) ([2c11c61](https://github.com/parse-community/parse-server/commit/2c11c616cb911ceed322c8d4dd204de9a0abc323))
## [8.6.18](https://github.com/parse-community/parse-server/compare/8.6.17...8.6.18) (2026-03-08)
### Bug Fixes
* Missing audience validation in Keycloak authentication adapter ([GHSA-48mh-j4p5-7j9v](https://github.com/parse-community/parse-server/security/advisories/GHSA-48mh-j4p5-7j9v)) ([#10138](https://github.com/parse-community/parse-server/issues/10138)) ([572be64](https://github.com/parse-community/parse-server/commit/572be64d17935870a94840fe541ae91cc09143c2))
## [8.6.17](https://github.com/parse-community/parse-server/compare/8.6.16...8.6.17) (2026-03-08)
### Bug Fixes
* Stored cross-site scripting (XSS) via SVG file upload ([GHSA-hcj7-6gxh-24ww](https://github.com/parse-community/parse-server/security/advisories/GHSA-hcj7-6gxh-24ww)) ([#10135](https://github.com/parse-community/parse-server/issues/10135)) ([fed2d39](https://github.com/parse-community/parse-server/commit/fed2d39f1dc4a64d093e77d54ebc7f6963918d15))
## [8.6.16](https://github.com/parse-community/parse-server/compare/8.6.15...8.6.16) (2026-03-08)
### Bug Fixes
* Bypass of class-level permissions in LiveQuery ([GHSA-7ch5-98q2-7289](https://github.com/parse-community/parse-server/security/advisories/GHSA-7ch5-98q2-7289)) ([#10134](https://github.com/parse-community/parse-server/issues/10134)) ([6fecec5](https://github.com/parse-community/parse-server/commit/6fecec52c53f24baefbfd5b5899bf295069447d6))
## [8.6.15](https://github.com/parse-community/parse-server/compare/8.6.14...8.6.15) (2026-03-07)
### Bug Fixes
* Denial-of-service via unbounded query complexity in REST and GraphQL API ([GHSA-cmj3-wx7h-ffvg](https://github.com/parse-community/parse-server/security/advisories/GHSA-cmj3-wx7h-ffvg)) ([#10131](https://github.com/parse-community/parse-server/issues/10131)) ([23ac059](https://github.com/parse-community/parse-server/commit/23ac05938b64451322b60fe6b031b4893ff62b67))
## [8.6.14](https://github.com/parse-community/parse-server/compare/8.6.13...8.6.14) (2026-03-07)
### Bug Fixes
* NoSQL injection via token type in password reset and email verification endpoints ([GHSA-vgjh-hmwf-c588](https://github.com/parse-community/parse-server/security/advisories/GHSA-vgjh-hmwf-c588)) ([#10129](https://github.com/parse-community/parse-server/issues/10129)) ([88eed83](https://github.com/parse-community/parse-server/commit/88eed83ff818027a960274e1de30a487812a6db4))
## [8.6.13](https://github.com/parse-community/parse-server/compare/8.6.12...8.6.13) (2026-03-07)
### Bug Fixes
* Denial of Service (DoS) and Cloud Function Dispatch Bypass via Prototype Chain Resolution ([GHSA-5j86-7r7m-p8h6](https://github.com/parse-community/parse-server/security/advisories/GHSA-5j86-7r7m-p8h6)) ([#10124](https://github.com/parse-community/parse-server/issues/10124)) ([5c2d60a](https://github.com/parse-community/parse-server/commit/5c2d60a2f3733ca3a4cb782d552ba38c526aee0b))
## [8.6.12](https://github.com/parse-community/parse-server/compare/8.6.11...8.6.12) (2026-03-07)
### Bug Fixes
* Denylist `requestKeywordDenylist` keyword scan bypass through nested object placement ([GHSA-q342-9w2p-57fp](https://github.com/parse-community/parse-server/security/advisories/GHSA-q342-9w2p-57fp)) ([#10122](https://github.com/parse-community/parse-server/issues/10122)) ([2b52feb](https://github.com/parse-community/parse-server/commit/2b52feb06448e5c683017fa2e3d2038a5d8d6085))
## [8.6.11](https://github.com/parse-community/parse-server/compare/8.6.10...8.6.11) (2026-03-07)
### Bug Fixes
* Regular Expression Denial of Service (ReDoS) via `$regex` query in LiveQuery ([GHSA-mf3j-86qx-cq5j](https://github.com/parse-community/parse-server/security/advisories/GHSA-mf3j-86qx-cq5j)) ([#10120](https://github.com/parse-community/parse-server/issues/10120)) ([42bd2f0](https://github.com/parse-community/parse-server/commit/42bd2f07bd3b425cac1e3c48161688cc4d54ef41))
## [8.6.10](https://github.com/parse-community/parse-server/compare/8.6.9...8.6.10) (2026-03-06)
### Bug Fixes
* JWT audience validation bypass in Google, Apple, and Facebook authentication adapters ([GHSA-x6fw-778m-wr9v](https://github.com/parse-community/parse-server/security/advisories/GHSA-x6fw-778m-wr9v)) ([#10114](https://github.com/parse-community/parse-server/issues/10114)) ([1da3123](https://github.com/parse-community/parse-server/commit/1da312311827a7790ad97852e8672119d40d529a))
## [8.6.9](https://github.com/parse-community/parse-server/compare/8.6.8...8.6.9) (2026-03-06)
### Bug Fixes
* File metadata endpoint bypasses `beforeFind` / `afterFind` trigger authorization ([GHSA-hwx8-q9cg-mqmc](https://github.com/parse-community/parse-server/security/advisories/GHSA-hwx8-q9cg-mqmc)) ([#10107](https://github.com/parse-community/parse-server/issues/10107)) ([a7358b1](https://github.com/parse-community/parse-server/commit/a7358b1e0c58ef4c6b5e0ade772bf673b5f78fd0))
## [8.6.8](https://github.com/parse-community/parse-server/compare/8.6.7...8.6.8) (2026-03-05)
### Bug Fixes
* `PagesRouter` path traversal allows reading files outside configured pages directory ([GHSA-hm3f-q6rw-m6wh](https://github.com/parse-community/parse-server/security/advisories/GHSA-hm3f-q6rw-m6wh)) ([#10105](https://github.com/parse-community/parse-server/issues/10105)) ([d5a057d](https://github.com/parse-community/parse-server/commit/d5a057d1a7cd5f6713d93afa3ad6f764f74b6ed2))
## [8.6.7](https://github.com/parse-community/parse-server/compare/8.6.6...8.6.7) (2026-03-05)
### Bug Fixes
* Malformed `$regex` query leaks database error details in API response (GHSA-9cp7-3q5w-j92g) ([#10102](https://github.com/parse-community/parse-server/issues/10102)) ([07870f5](https://github.com/parse-community/parse-server/commit/07870f59eec03f5c2a5fb1732cb28787ca3f8152))
## [8.6.6](https://github.com/parse-community/parse-server/compare/8.6.5...8.6.6) (2026-03-05)
### Bug Fixes
* Endpoint `/loginAs` allows `readOnlyMasterKey` to gain full read and write access as any user ([GHSA-79wj-8rqv-jvp5](https://github.com/parse-community/parse-server/security/advisories/GHSA-79wj-8rqv-jvp5)) ([#10099](https://github.com/parse-community/parse-server/issues/10099)) ([0c940b7](https://github.com/parse-community/parse-server/commit/0c940b70891c947fbf6c55536ed95ae300c23350))
## [8.6.5](https://github.com/parse-community/parse-server/compare/8.6.4...8.6.5) (2026-03-05)
### Bug Fixes
* File creation and deletion bypasses `readOnlyMasterKey` write restriction (GHSA-xfh7-phr7-gr2x) ([#10096](https://github.com/parse-community/parse-server/issues/10096)) ([07bddc0](https://github.com/parse-community/parse-server/commit/07bddc0850c0eebb51219fe1d5d342f4412461ba))
## [8.6.4](https://github.com/parse-community/parse-server/compare/8.6.3...8.6.4) (2026-03-04)
### Bug Fixes
* Cloud Hooks and Cloud Jobs bypass `readOnlyMasterKey` write restriction (GHSA-vc89-5g3r-cmhh) ([#10089](https://github.com/parse-community/parse-server/issues/10089)) ([6c79da9](https://github.com/parse-community/parse-server/commit/6c79da91fc5ec6f2a0bb69a0ca6a886c1585754f))
## [8.6.3](https://github.com/parse-community/parse-server/compare/8.6.2...8.6.3) (2026-02-23)
### Bug Fixes
* JWT Algorithm Confusion in Google Auth Adapter ([GHSA-4q3h-vp4r-prv2](https://github.com/parse-community/parse-server/security/advisories/GHSA-4q3h-vp4r-prv2)) ([#10073](https://github.com/parse-community/parse-server/issues/10073)) ([9b94083](https://github.com/parse-community/parse-server/commit/9b94083accb7f3e72c6b8126c195c7a03dd2dfd7))
## [8.6.2](https://github.com/parse-community/parse-server/compare/8.6.1...8.6.2) (2025-12-16)
### Bug Fixes
* Server-Side Request Forgery (SSRF) in Instagram auth adapter [GHSA-3f5f-xgrj-97pf](https://github.com/parse-community/parse-server/security/advisories/GHSA-3f5f-xgrj-97pf) ([#9989](https://github.com/parse-community/parse-server/issues/9989)) ([155c6ad](https://github.com/parse-community/parse-server/commit/155c6ad92d2375652c9720d7deed129a9e8f74ff))
## [8.6.1](https://github.com/parse-community/parse-server/compare/8.6.0...8.6.1) (2025-12-14)
### Bug Fixes
* Cross-Site Scripting (XSS) via HTML pages for password reset and email verification [GHSA-jhgf-2h8h-ggxv](https://github.com/parse-community/parse-server/security/advisories/GHSA-jhgf-2h8h-ggxv) ([#9986](https://github.com/parse-community/parse-server/issues/9986)) ([12d8b50](https://github.com/parse-community/parse-server/commit/12d8b502a2f99098d177d095842b07d55f62313a))
# [8.6.0](https://github.com/parse-community/parse-server/compare/8.5.0...8.6.0) (2025-12-10)
### Bug Fixes
* Remove elevated permissions in GitHub CI performance benchmark ([#9966](https://github.com/parse-community/parse-server/issues/9966)) ([6b9f896](https://github.com/parse-community/parse-server/commit/6b9f8963cc3debf59cd9c5dfc5422aff9404ce9d))
### Features
* Add GraphQL query `cloudConfig` to retrieve and mutation `updateCloudConfig` to update Cloud Config ([#9947](https://github.com/parse-community/parse-server/issues/9947)) ([3ca85cd](https://github.com/parse-community/parse-server/commit/3ca85cd4a632f234c9d3d731331c0524dfe54075))
# [8.5.0](https://github.com/parse-community/parse-server/compare/8.4.0...8.5.0) (2025-12-01)
### Bug Fixes
* `GridFSBucketAdapter` throws when using some Parse Server specific options in MongoDB database options ([#9915](https://github.com/parse-community/parse-server/issues/9915)) ([d3d4003](https://github.com/parse-community/parse-server/commit/d3d4003570b9872f2b0f5a25fc06ce4c4132860d))
* Deprecation warning logged at server launch for nested Parse Server option even if option is explicitly set ([#9934](https://github.com/parse-community/parse-server/issues/9934)) ([c22cb0a](https://github.com/parse-community/parse-server/commit/c22cb0ae58e64cd0e4597ab9610d57a1155c44a2))
* Parse Server option `rateLimit.zone` does not use default value `ip` ([#9941](https://github.com/parse-community/parse-server/issues/9941)) ([12beb8f](https://github.com/parse-community/parse-server/commit/12beb8f6ee5d3002fec017bb4525eb3f1375f806))
* Queries with object field `authData.provider.id` are incorrectly transformed to `_auth_data_provider.id` for custom classes ([#9932](https://github.com/parse-community/parse-server/issues/9932)) ([7b9fa18](https://github.com/parse-community/parse-server/commit/7b9fa18f968ec084ea0b35dad2b5ba0451d59787))
* Race condition can cause multiple Apollo server initializations under load ([#9929](https://github.com/parse-community/parse-server/issues/9929)) ([7d5e9fc](https://github.com/parse-community/parse-server/commit/7d5e9fcf3ceb0abad8ab49c75bc26f521a0f1bde))
* Server internal error details leaking in error messages returned to clients ([#9937](https://github.com/parse-community/parse-server/issues/9937)) ([50edb5a](https://github.com/parse-community/parse-server/commit/50edb5ab4bb4a6ce474bfb7cf159d918933753b8))
### Features
* Add `beforePasswordResetRequest` hook ([#9906](https://github.com/parse-community/parse-server/issues/9906)) ([94cee5b](https://github.com/parse-community/parse-server/commit/94cee5bfafca10c914c73cf17fcdb627a9f0837b))
* Add MongoDB client event logging via database option `logClientEvents` ([#9914](https://github.com/parse-community/parse-server/issues/9914)) ([b760733](https://github.com/parse-community/parse-server/commit/b760733b98bcfc9c09ac9780066602e1fda108fe))
* Add Parse Server option `allowPublicExplain` to allow `Parse.Query.explain` without master key ([#9890](https://github.com/parse-community/parse-server/issues/9890)) ([4456b02](https://github.com/parse-community/parse-server/commit/4456b02280c2d8dd58b7250e9e67f1a8647b3452))
* Add Parse Server option `enableSanitizedErrorResponse` to remove detailed error messages from responses sent to clients ([#9944](https://github.com/parse-community/parse-server/issues/9944)) ([4752197](https://github.com/parse-community/parse-server/commit/47521974aeafcf41102be62f19612a4ab0a4837f))
* Add support for MongoDB driver options `serverSelectionTimeoutMS`, `maxIdleTimeMS`, `heartbeatFrequencyMS` ([#9910](https://github.com/parse-community/parse-server/issues/9910)) ([1b661e9](https://github.com/parse-community/parse-server/commit/1b661e98c86a1db79e076a7297cd9199a72ae1ac))
* Add support for more MongoDB driver options ([#9911](https://github.com/parse-community/parse-server/issues/9911)) ([cff451e](https://github.com/parse-community/parse-server/commit/cff451eabdc380affa600ed711de66f7bd1d00aa))
* Allow option `publicServerURL` to be set dynamically as asynchronous function ([#9803](https://github.com/parse-community/parse-server/issues/9803)) ([460a65c](https://github.com/parse-community/parse-server/commit/460a65cf612f4c86af8038cafcc7e7ffe9eb8440))
* Upgrade to parse 7.1.1 ([#9954](https://github.com/parse-community/parse-server/issues/9954)) ([fa57d69](https://github.com/parse-community/parse-server/commit/fa57d69cbec525189da98d7136c1c0e9eaf74338))
* Upgrade to parse 7.1.2 ([#9955](https://github.com/parse-community/parse-server/issues/9955)) ([5c644a5](https://github.com/parse-community/parse-server/commit/5c644a55ac25986f214b68ba4bcbe7a62ad6d6d1))
### Performance Improvements
* `Parse.Query.include` now fetches pointers at same level in parallel ([#9861](https://github.com/parse-community/parse-server/issues/9861)) ([dafea21](https://github.com/parse-community/parse-server/commit/dafea21eb39b0fdc2b52bb8a14f7b61e3f2b8d13))
* Remove unused dependencies ([#9943](https://github.com/parse-community/parse-server/issues/9943)) ([d4c6de0](https://github.com/parse-community/parse-server/commit/d4c6de0096b3ac95289c6bddfe25eb397d790e41))
* Upgrade MongoDB driver to 6.20.0 ([#9887](https://github.com/parse-community/parse-server/issues/9887)) ([3c9af48](https://github.com/parse-community/parse-server/commit/3c9af48edd999158443b797e388e29495953799e))
# [8.4.0](https://github.com/parse-community/parse-server/compare/8.3.0...8.4.0) (2025-11-05)
### Bug Fixes
* Add problematic MIME types to default value of Parse Server option `fileUpload.fileExtensions` ([#9902](https://github.com/parse-community/parse-server/issues/9902)) ([fa245cb](https://github.com/parse-community/parse-server/commit/fa245cbb5f5b7a0dad962b2ce0524fa4dafcb5f7))
* Uploading a file by providing an origin URL allows for Server-Side Request Forgery (SSRF); fixes vulnerability [GHSA-x4qj-2f4q-r4rx](https://github.com/parse-community/parse-server/security/advisories/GHSA-x4qj-2f4q-r4rx) ([#9903](https://github.com/parse-community/parse-server/issues/9903)) ([9776386](https://github.com/parse-community/parse-server/commit/97763863b72689a29ad7a311dfb590c3e3c50585))
### Features
* Add support for Node 24 ([#9901](https://github.com/parse-community/parse-server/issues/9901)) ([25dfe19](https://github.com/parse-community/parse-server/commit/25dfe19fef02fd44224e4a6d198584a694a1aa52))
# [8.3.0](https://github.com/parse-community/parse-server/compare/8.2.5...8.3.0) (2025-11-01)
### Bug Fixes
* Error in `afterSave` trigger for `Parse.Role` due to `name` field ([#9883](https://github.com/parse-community/parse-server/issues/9883)) ([eb052d8](https://github.com/parse-community/parse-server/commit/eb052d8e6abe1ae32505fd068d5445eaf950a770))
* Indexes `_email_verify_token` for email verification and `_perishable_token` password reset are not created automatically ([#9893](https://github.com/parse-community/parse-server/issues/9893)) ([62dd3c5](https://github.com/parse-community/parse-server/commit/62dd3c565ab70765cb1c547996b616b72e9bb800))
* Security upgrade to parse 7.0.1 ([#9877](https://github.com/parse-community/parse-server/issues/9877)) ([abfa94c](https://github.com/parse-community/parse-server/commit/abfa94cd6de2c4e76337931c8ea8311c4ccf2a1a))
* Server URL verification before server is ready ([#9882](https://github.com/parse-community/parse-server/issues/9882)) ([178bd5c](https://github.com/parse-community/parse-server/commit/178bd5c5e258d9501c9ac4d35a3a105ab64be67e))
* Stale data read in validation query on `Parse.Object` update causes inconsistency between validation read and subsequent update write operation ([#9859](https://github.com/parse-community/parse-server/issues/9859)) ([f49efaf](https://github.com/parse-community/parse-server/commit/f49efaf5bb1d6b19f6d6712f7cdf073855c95c6e))
* Warning logged when setting option `databaseOptions.disableIndexFieldValidation` ([#9880](https://github.com/parse-community/parse-server/issues/9880)) ([1815b01](https://github.com/parse-community/parse-server/commit/1815b019b52565d2bc87be2596a49aea7600aeba))
### Features
* Add option `keepUnknownIndexes` to retain indexes which are not specified in schema ([#9857](https://github.com/parse-community/parse-server/issues/9857)) ([89fad46](https://github.com/parse-community/parse-server/commit/89fad468c3a43772879c06c4d939a83b72517a8e))
* Add options to skip automatic creation of internal database indexes on server start ([#9897](https://github.com/parse-community/parse-server/issues/9897)) ([ea91aca](https://github.com/parse-community/parse-server/commit/ea91aca1420c33e038516a321b2640709589f886))
* Add Parse Server option `verifyServerUrl` to disable server URL verification on server launch ([#9881](https://github.com/parse-community/parse-server/issues/9881)) ([b298ccc](https://github.com/parse-community/parse-server/commit/b298cccd9fb4f664b9d83894faad6d1ea7a3c964))
* Add regex option `u` for unicode support in `Parse.Query.matches` for MongoDB ([#9867](https://github.com/parse-community/parse-server/issues/9867)) ([7cb962a](https://github.com/parse-community/parse-server/commit/7cb962a02845f3dded61baffd84515f94b66ee50))
* Add request context middleware for config and dependency injection in hooks ([#8480](https://github.com/parse-community/parse-server/issues/8480)) ([64f104e](https://github.com/parse-community/parse-server/commit/64f104e5c5f8863098e801eee632c14fcbd9b6f9))
* Add support for Postgres 18 ([#9870](https://github.com/parse-community/parse-server/issues/9870)) ([d275c18](https://github.com/parse-community/parse-server/commit/d275c1806e0a5a037cc06cde7eefff3e12c91d7d))
* Allow returning objects in `Parse.Cloud.beforeFind` without invoking database query ([#9770](https://github.com/parse-community/parse-server/issues/9770)) ([0b47407](https://github.com/parse-community/parse-server/commit/0b4740714c29ba99672bc535619ee3516abd356f))
* Disable index-field validation to create index for fields that don't yet exist ([#8137](https://github.com/parse-community/parse-server/issues/8137)) ([1b23475](https://github.com/parse-community/parse-server/commit/1b2347524ca84ade0f6badf175a815fc8a7bef49))
## [8.2.5](https://github.com/parse-community/parse-server/compare/8.2.4...8.2.5) (2025-10-02)
### Bug Fixes
* GraphQL playground shows blank page ([#9858](https://github.com/parse-community/parse-server/issues/9858)) ([7b5395c](https://github.com/parse-community/parse-server/commit/7b5395c5d481235c022d96603280672366a50715))
## [8.2.4](https://github.com/parse-community/parse-server/compare/8.2.3...8.2.4) (2025-09-01)
### Bug Fixes
* Security upgrade form-data from 4.0.3 to 4.0.4 ([#9829](https://github.com/parse-community/parse-server/issues/9829)) ([c2c593f](https://github.com/parse-community/parse-server/commit/c2c593f437c33f37101b4f3bb1287eef31dbbc3b))
## [8.2.3](https://github.com/parse-community/parse-server/compare/8.2.2...8.2.3) (2025-08-01)
### Bug Fixes
* MongoDB aggregation pipeline with `$dateSubtract` from `$$NOW` returns no results ([#9822](https://github.com/parse-community/parse-server/issues/9822)) ([847a274](https://github.com/parse-community/parse-server/commit/847a274cdb8c22f8e0fc249162e5e2c9e29a594a))
## [8.2.2](https://github.com/parse-community/parse-server/compare/8.2.1...8.2.2) (2025-07-10)
### Bug Fixes
* Data schema exposed via GraphQL API public introspection (GHSA-48q3-prgv-gm4w) ([#9819](https://github.com/parse-community/parse-server/issues/9819)) ([c58b2eb](https://github.com/parse-community/parse-server/commit/c58b2eb6eb48af9d3c2e69b4829810a021347b40))
## [8.2.1](https://github.com/parse-community/parse-server/compare/8.2.0...8.2.1) (2025-06-01)
### Bug Fixes
* `Parse.Query.containedIn` and `matchesQuery` do not work with nested objects ([#9738](https://github.com/parse-community/parse-server/issues/9738)) ([0db3a6f](https://github.com/parse-community/parse-server/commit/0db3a6ff27a129427770e314a792cc586e4255b5))
### Performance Improvements
* Remove saving Parse Cloud Job request parameters in internal collection `_JobStatus` ([#8343](https://github.com/parse-community/parse-server/issues/8343)) ([e98733c](https://github.com/parse-community/parse-server/commit/e98733cbac9451521a3acc388d2f9d29eb4610e0))
# [8.2.0](https://github.com/parse-community/parse-server/compare/8.1.0...8.2.0) (2025-05-01)
### Features
* Add TypeScript definitions ([#9693](https://github.com/parse-community/parse-server/issues/9693)) ([e86718f](https://github.com/parse-community/parse-server/commit/e86718fc59c7c8e6f3c6abd0feb7d1a68ca76c23))
### Performance Improvements
* Add details to error message in `Parse.Query.aggregate` ([#9689](https://github.com/parse-community/parse-server/issues/9689)) ([9de6999](https://github.com/parse-community/parse-server/commit/9de6999e257d839b68bbca282447777edfdb1ddf))
# [8.1.0](https://github.com/parse-community/parse-server/compare/8.0.2...8.1.0) (2025-04-04)
### Bug Fixes
* Parse Server doesn't shutdown gracefully ([#9634](https://github.com/parse-community/parse-server/issues/9634)) ([aed918d](https://github.com/parse-community/parse-server/commit/aed918d3109e739f7231d481b5f48c68fc01cf04))
### Features
* Add Cloud Code triggers `Parse.Cloud.beforeFind(Parse.File)`and `Parse.Cloud.afterFind(Parse.File)` ([#8700](https://github.com/parse-community/parse-server/issues/8700)) ([b2beaa8](https://github.com/parse-community/parse-server/commit/b2beaa86ff543a7aa4ad274c7a23bc4aa302c3fa))
* Add default ACL ([#8701](https://github.com/parse-community/parse-server/issues/8701)) ([12b5d78](https://github.com/parse-community/parse-server/commit/12b5d781dc3f8c43c0c566dffa9308d02a7d8043))
* Upgrade Parse JS SDK from 6.0.0 to 6.1.0 ([#9686](https://github.com/parse-community/parse-server/issues/9686)) ([f49c371](https://github.com/parse-community/parse-server/commit/f49c371c1373d41e68b091e65f33a71ff6fc6dd0))
## [8.0.2](https://github.com/parse-community/parse-server/compare/8.0.1...8.0.2) (2025-03-21)
### Bug Fixes
* Authentication provider credentials are usable across Parse Server apps; fixes security vulnerability [GHSA-837q-jhwx-cmpv](https://github.com/parse-community/parse-server/security/advisories/GHSA-837q-jhwx-cmpv) ([#9667](https://github.com/parse-community/parse-server/issues/9667)) ([5ef0440](https://github.com/parse-community/parse-server/commit/5ef0440c8e763854e62341acaeb6dc4ade3ba82f))
## [8.0.1](https://github.com/parse-community/parse-server/compare/8.0.0...8.0.1) (2025-03-17)
### Bug Fixes
* Security upgrade node from 20.18.2-alpine3.20 to 20.19.0-alpine3.20 ([#9652](https://github.com/parse-community/parse-server/issues/9652)) ([2be1a19](https://github.com/parse-community/parse-server/commit/2be1a19a13d6f0f8e3eb4e399a6279ff4d01db76))
* Using Parse Server option `extendSessionOnUse` does not correctly clear memory and functions as a debounce instead of a throttle ([#8683](https://github.com/parse-community/parse-server/issues/8683)) ([6258a6a](https://github.com/parse-community/parse-server/commit/6258a6a11235dc642c71074d24e19c055294d26d))
# [8.0.0](https://github.com/parse-community/parse-server/compare/7.4.0...8.0.0) (2025-03-04)
### Bug Fixes
* LiveQueryServer crashes using cacheAdapter on disconnect from Redis 4 server ([#9616](https://github.com/parse-community/parse-server/issues/9616)) ([bbc6bd4](https://github.com/parse-community/parse-server/commit/bbc6bd4b3f493170c13ad3314924cbf1f379eca4))
* Push adapter not loading on some versions of Node 22 ([#9524](https://github.com/parse-community/parse-server/issues/9524)) ([ff7f671](https://github.com/parse-community/parse-server/commit/ff7f671c79f5dcdc44e4319a10f3654e12662c23))
* Remove username from email verification and password reset process ([#8488](https://github.com/parse-community/parse-server/issues/8488)) ([d21dd97](https://github.com/parse-community/parse-server/commit/d21dd973363f9c5eca86a1007cb67e445b0d2e02))
* Security upgrade node from 20.17.0-alpine3.20 to 20.18.2-alpine3.20 ([#9583](https://github.com/parse-community/parse-server/issues/9583)) ([8f85ae2](https://github.com/parse-community/parse-server/commit/8f85ae205474f65414c0536754de12c87dbbf82a))
### Features
* Add dynamic master key by setting Parse Server option `masterKey` to a function ([#9582](https://github.com/parse-community/parse-server/issues/9582)) ([6f1d161](https://github.com/parse-community/parse-server/commit/6f1d161a2f263a166981f9544cf2aadce65afe23))
* Add support for MongoDB `databaseOptions` keys `autoSelectFamily`, `autoSelectFamilyAttemptTimeout` ([#9579](https://github.com/parse-community/parse-server/issues/9579)) ([5966068](https://github.com/parse-community/parse-server/commit/5966068e963e7a79eac8fba8720ee7d83578f207))
* Add support for MongoDB `databaseOptions` keys `minPoolSize`, `connectTimeoutMS`, `socketTimeoutMS` ([#9522](https://github.com/parse-community/parse-server/issues/9522)) ([91618fe](https://github.com/parse-community/parse-server/commit/91618fe738217b937cbfcec35969679e0adb7676))
* Add TypeScript support ([#9550](https://github.com/parse-community/parse-server/issues/9550)) ([59e46d0](https://github.com/parse-community/parse-server/commit/59e46d0aea3e6529994d98160d993144b8075291))
* Change default value of Parse Server option `encodeParseObjectInCloudFunction` to `true` ([#9527](https://github.com/parse-community/parse-server/issues/9527)) ([5c5ad69](https://github.com/parse-community/parse-server/commit/5c5ad69b4a917b7ed7c328a8255144e105c40b08))
* Deprecate `PublicAPIRouter` in favor of `PagesRouter` ([#9526](https://github.com/parse-community/parse-server/issues/9526)) ([7f66629](https://github.com/parse-community/parse-server/commit/7f666292e8b9692966672486b7108edefc356309))
* Increase required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` ([#9531](https://github.com/parse-community/parse-server/issues/9531)) ([871e508](https://github.com/parse-community/parse-server/commit/871e5082a9fd768cee3012e26d3c8ddff5c2952c))
* Increase required minimum Node versions to `18.20.4`, `20.18.0`, `22.12.0` ([#9521](https://github.com/parse-community/parse-server/issues/9521)) ([4e151cd](https://github.com/parse-community/parse-server/commit/4e151cd0a52191809452f197b2f29c3a12525b67))
* Increase required minimum versions to Postgres `15`, PostGIS `3.3` ([#9538](https://github.com/parse-community/parse-server/issues/9538)) ([89c9b54](https://github.com/parse-community/parse-server/commit/89c9b5485a07a411fb35de4f8cf0467e7eb01f85))
* Upgrade to express 5.0.1 ([#9530](https://github.com/parse-community/parse-server/issues/9530)) ([e0480df](https://github.com/parse-community/parse-server/commit/e0480dfa8d97946e57eac6b74d937978f8454b3a))
* Upgrade to Parse JS SDK 6.0.0 ([#9624](https://github.com/parse-community/parse-server/issues/9624)) ([bf9db75](https://github.com/parse-community/parse-server/commit/bf9db75e8685def1407034944725e758bc926c26))
### BREAKING CHANGES
* This upgrades the internally used Express framework from version 4 to 5, which may be a breaking change. If Parse Server is set up to be mounted on an Express application, we recommend to also use version 5 of the Express framework to avoid any compatibility issues. Note that even if there are no issues after upgrading, future releases of Parse Server may introduce issues if Parse Server internally relies on Express 5-specific features which are unsupported by the Express version on which it is mounted. See the Express [migration guide](https://expressjs.com/en/guide/migrating-5.html) and [release announcement](https://expressjs.com/2024/10/15/v5-release.html#breaking-changes) for more info. ([e0480df](e0480df))
* This upgrades to the Parse JS SDK 6.0.0. See the [change log](https://github.com/parse-community/Parse-SDK-JS/releases/tag/6.0.0) of the Parse JS SDK for breaking changes and more details. ([bf9db75](bf9db75))
* This removes the username from the email verification and password reset process to prevent storing personally identifiable information (PII) in server and infrastructure logs. Customized HTML pages or emails related to email verification and password reset may need to be adapted accordingly. See the new templates that come bundled with Parse Server and the [migration guide](https://github.com/parse-community/parse-server/blob/alpha/8.0.0.md) for more details. ([d21dd97](d21dd97))
* This releases increases the required minimum versions to Postgres `15`, PostGIS `3.3` and removes support for Postgres `13`, `14`, PostGIS `3.1`, `3.2`. ([89c9b54](89c9b54))
* The default value of Parse Server option `encodeParseObjectInCloudFunction` changes to `true`; the option has been deprecated and will be removed in a future version. ([5c5ad69](5c5ad69))
* This releases increases the required minimum MongoDB versions to `6.0.19`, `7.0.16`, `8.0.4` and removes support for MongoDB `4`, `5`. ([871e508](871e508))
* This releases increases the required minimum Node versions to 18.20.4, 20.18.0, 22.12.0 and removes unofficial support for Node 19. ([4e151cd](4e151cd))
# [7.4.0](https://github.com/parse-community/parse-server/compare/7.3.0...7.4.0) (2024-12-23)
### Bug Fixes
* `Parse.Query.distinct` fails due to invalid aggregate stage 'hint' ([#9295](https://github.com/parse-community/parse-server/issues/9295)) ([5f66c6a](https://github.com/parse-community/parse-server/commit/5f66c6a075cbe1cdaf9d1b108ee65af8ae596b89))
* Security upgrade cross-spawn from 7.0.3 to 7.0.6 ([#9444](https://github.com/parse-community/parse-server/issues/9444)) ([3d034e0](https://github.com/parse-community/parse-server/commit/3d034e0a993e3e5bd9bb96a7e382bb3464f1eb68))
* Security upgrade fast-xml-parser from 4.4.0 to 4.4.1 ([#9262](https://github.com/parse-community/parse-server/issues/9262)) ([992d39d](https://github.com/parse-community/parse-server/commit/992d39d508f230c774dcb764d1d907ec8887e6c5))
* Security upgrade node from 20.14.0-alpine3.20 to 20.17.0-alpine3.20 ([#9300](https://github.com/parse-community/parse-server/issues/9300)) ([15bb17d](https://github.com/parse-community/parse-server/commit/15bb17d87153bf0d38f08fe4c720da29a204b36b))
### Features
* Add support for MongoDB 8 ([#9269](https://github.com/parse-community/parse-server/issues/9269)) ([4756c66](https://github.com/parse-community/parse-server/commit/4756c66cd9f55afa1621d1a3f6fa850ed605cb53))
* Add support for PostGIS 3.5 ([#9354](https://github.com/parse-community/parse-server/issues/9354)) ([8ea3538](https://github.com/parse-community/parse-server/commit/8ea35382db3436d54ab59bd30706705564b0985c))
* Add support for Postgres 17 ([#9324](https://github.com/parse-community/parse-server/issues/9324)) ([fa2ee31](https://github.com/parse-community/parse-server/commit/fa2ee3196e4319a142b3838bb947c98dcba5d5cb))
* Upgrade @parse/push-adapter from 6.7.1 to 6.8.0 ([#9489](https://github.com/parse-community/parse-server/issues/9489)) ([286aa66](https://github.com/parse-community/parse-server/commit/286aa664ac8830d36c3e70d2316917d15f0b6df5))
# [7.3.0](https://github.com/parse-community/parse-server/compare/7.2.0...7.3.0) (2024-10-03)
### Bug Fixes
* Custom object ID allows to acquire role privileges ([GHSA-8xq9-g7ch-35hg](https://github.com/parse-community/parse-server/security/advisories/GHSA-8xq9-g7ch-35hg)) ([#9317](https://github.com/parse-community/parse-server/issues/9317)) ([13ee52f](https://github.com/parse-community/parse-server/commit/13ee52f0d19ef3a3524b3d79aea100e587eb3cfc))
* Parse Server `databaseOptions` nested keys incorrectly identified as invalid ([#9213](https://github.com/parse-community/parse-server/issues/9213)) ([77206d8](https://github.com/parse-community/parse-server/commit/77206d804443cfc1618c24f8961bd677de9920c0))
* Parse Server installation fails due to post install script incorrectly parsing required min. Node version ([#9216](https://github.com/parse-community/parse-server/issues/9216)) ([0fa82a5](https://github.com/parse-community/parse-server/commit/0fa82a54fe38ec14e8054339285d3db71a8624c8))
* Parse Server option `maxLogFiles` doesn't recognize day duration literals such as `1d` to mean 1 day ([#9215](https://github.com/parse-community/parse-server/issues/9215)) ([0319cee](https://github.com/parse-community/parse-server/commit/0319cee2dbf65e90bad377af1ed14ea25c595bf5))
* Security upgrade path-to-regexp from 6.2.1 to 6.3.0 ([#9314](https://github.com/parse-community/parse-server/issues/9314)) ([8b7fe69](https://github.com/parse-community/parse-server/commit/8b7fe699c1c376ecd8cc1c97cce8e704ee41f28a))
### Features
* Add atomic operations for Cloud Config parameters ([#9219](https://github.com/parse-community/parse-server/issues/9219)) ([35cadf9](https://github.com/parse-community/parse-server/commit/35cadf9b8324879fb7309ba5d7ea46f2c722d614))
* Add Cloud Code triggers `Parse.Cloud.beforeSave` and `Parse.Cloud.afterSave` for Parse Config ([#9232](https://github.com/parse-community/parse-server/issues/9232)) ([90a1e4a](https://github.com/parse-community/parse-server/commit/90a1e4a200423d644efb3f0ba2fba4b99f5cf954))
* Add Node 22 support ([#9187](https://github.com/parse-community/parse-server/issues/9187)) ([7778471](https://github.com/parse-community/parse-server/commit/7778471999c7e42236ce404229660d80ecc2acd6))
* Add support for asynchronous invocation of `FilesAdapter.getFileLocation` ([#9271](https://github.com/parse-community/parse-server/issues/9271)) ([1a2da40](https://github.com/parse-community/parse-server/commit/1a2da4055abe831b3017172fb75e16d7a8093873))
# [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)
+2
View File
@@ -220,6 +220,7 @@ class CiVersionCheck {
* Runs the check.
*/
async check() {
/* eslint-disable no-console */
try {
console.log(`\nChecking ${this.packageName} versions in CI environments...`);
@@ -284,6 +285,7 @@ class CiVersionCheck {
const msg = `Failed to check ${this.packageName} versions with error: ${e}`;
core.setFailed(msg);
}
/* eslint-enable no-console */
}
}
+20 -18
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,13 +30,14 @@ async function checkMongoDbVersions() {
yamlFilePath: './.github/workflows/ci.yml',
ciEnvironmentsKeyPath: 'jobs.check-mongo.strategy.matrix.include',
ciVersionKey: 'MONGODB_VERSION',
releasedVersions,
latestComponent: CiVersionCheck.versionComponents.minor,
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.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();
}
@@ -44,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',
@@ -53,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();
}
+1
View File
@@ -14,6 +14,7 @@ const util = require('util');
fs.readFile('./src/Options/docs.js', 'utf8'),
]);
if (currentDefinitions !== newDefinitions || currentDocs !== newDocs) {
// eslint-disable-next-line no-console
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.'
+4 -1
View File
@@ -86,7 +86,8 @@ class NodeEngineCheck {
file: file,
nodeVersion: version
});
} catch(e) {
} catch {
// eslint-disable-next-line no-console
console.log(`Ignoring file because it is not valid JSON: ${file}`);
core.warning(`Ignoring file because it is not valid JSON: ${file}`);
}
@@ -171,6 +172,7 @@ async function check() {
// Get highest version
const highestVersion = higherVersions.map(v => v.nodeMinVersion).pop();
/* eslint-disable no-console */
// If there are higher versions
if (higherVersions.length > 0) {
console.log(`\nThere are ${higherVersions.length} dependencies that require a higher node engine version than the parent package (${parentVersion.nodeVersion}):`);
@@ -189,6 +191,7 @@ async function check() {
}
console.log(`✅ All dependencies satisfy the node version requirement of the parent package (${parentVersion.nodeVersion}).`);
/* eslint-enable no-console */
}
check();
+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
+47
View File
@@ -0,0 +1,47 @@
const js = require("@eslint/js");
const babelParser = require("@babel/eslint-parser");
const globals = require("globals");
const unusedImports = require("eslint-plugin-unused-imports");
module.exports = [
{
ignores: ["**/lib/**", "**/coverage/**", "**/out/**", "**/types/**"],
},
js.configs.recommended,
{
languageOptions: {
parser: babelParser,
ecmaVersion: 6,
sourceType: "module",
globals: {
Parse: "readonly",
...globals.node,
},
parserOptions: {
requireConfigFile: false,
},
},
plugins: {
"unused-imports": unusedImports,
},
rules: {
indent: ["error", 2, { SwitchCase: 1 }],
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": "error",
"linebreak-style": ["error", "unix"],
"no-trailing-spaces": "error",
"eol-last": "error",
"space-in-parens": ["error", "never"],
"no-multiple-empty-lines": "warn",
"prefer-const": "error",
"space-infix-ops": "error",
"no-useless-escape": "off",
"require-atomic-updates": "off",
"object-curly-spacing": ["error", "always"],
curly: ["error", "all"],
"block-spacing": ["error", "always"],
"no-unused-vars": "off",
"no-console": "warn"
},
},
];
+6 -6
View File
@@ -6,10 +6,10 @@
"source": {
"include": [
"README.md",
"./src/cloud-code",
"./src/Options/docs.js",
"./src/ParseServer.js",
"./src/Adapters"
"./lib/cloud-code",
"./lib/Options/docs.js",
"./lib/ParseServer.js",
"./lib/Adapters"
],
"excludePattern": "(^|\\/|\\\\)_"
},
@@ -29,8 +29,8 @@
"template": "./node_modules/clean-jsdoc-theme",
"theme_opts": {
"default_theme": "dark",
"title": "<img src='../.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 }"
"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; height: auto; max-width: 100%; object-fit: contain; }"
}
},
"markdown": {
+20782 -19696
View File
File diff suppressed because it is too large Load Diff
+92 -90
View File
@@ -1,6 +1,6 @@
{
"name": "parse-server",
"version": "6.5.11",
"version": "8.6.50",
"description": "An express module providing a Parse-compatible API server",
"main": "lib/index.js",
"repository": {
@@ -15,97 +15,98 @@
"LICENSE",
"NOTICE",
"postinstall.js",
"README.md"
"README.md",
"types"
],
"license": "Apache-2.0",
"dependencies": {
"@babel/eslint-parser": "7.24.1",
"@graphql-tools/merge": "8.4.1",
"@graphql-tools/schema": "9.0.4",
"@graphql-tools/utils": "8.12.0",
"@graphql-yoga/node": "2.6.0",
"@parse/fs-files-adapter": "2.0.1",
"@parse/push-adapter": "5.1.1",
"bcryptjs": "2.4.3",
"body-parser": "1.20.3",
"commander": "10.0.1",
"@apollo/server": "4.12.1",
"@graphql-tools/merge": "9.0.24",
"@graphql-tools/schema": "10.0.23",
"@graphql-tools/utils": "10.8.6",
"@parse/fs-files-adapter": "3.0.0",
"@parse/push-adapter": "6.11.0",
"bcryptjs": "3.0.2",
"commander": "13.1.0",
"cors": "2.8.5",
"deepcopy": "2.1.0",
"express": "4.21.1",
"express-rate-limit": "6.7.0",
"follow-redirects": "1.15.6",
"graphql": "16.8.1",
"express": "5.2.1",
"express-rate-limit": "7.5.1",
"follow-redirects": "1.15.9",
"graphql": "16.11.0",
"graphql-list-fields": "2.0.4",
"graphql-relay": "0.10.1",
"graphql-tag": "2.12.6",
"graphql-relay": "0.10.2",
"graphql-upload": "15.0.2",
"intersect": "1.0.1",
"jsonwebtoken": "9.0.0",
"jwks-rsa": "3.1.0",
"ldapjs": "2.3.3",
"jsonwebtoken": "9.0.2",
"jwks-rsa": "3.2.0",
"ldapjs": "3.0.7",
"lodash": "4.17.21",
"lru-cache": "10.1.0",
"mime": "3.0.0",
"mongodb": "4.10.0",
"lru-cache": "10.4.0",
"mime": "4.0.7",
"mongodb": "6.20.0",
"mustache": "4.2.0",
"otpauth": "9.2.2",
"parse": "4.2.0",
"path-to-regexp": "6.2.2",
"pg-monitor": "2.0.0",
"pg-promise": "11.5.4",
"otpauth": "9.4.0",
"parse": "7.1.2",
"path-to-regexp": "6.3.0",
"pg-monitor": "3.0.0",
"pg-promise": "12.2.0",
"pluralize": "8.0.0",
"rate-limit-redis": "3.0.2",
"redis": "4.6.13",
"semver": "7.5.4",
"subscriptions-transport-ws": "0.11.0",
"punycode": "2.3.1",
"rate-limit-redis": "4.2.0",
"redis": "4.7.0",
"semver": "7.7.2",
"tv4": "1.3.0",
"uuid": "9.0.1",
"winston": "3.12.0",
"uuid": "11.1.0",
"winston": "3.17.0",
"winston-daily-rotate-file": "5.0.0",
"ws": "8.17.1"
"ws": "8.18.2"
},
"devDependencies": {
"@actions/core": "1.9.1",
"@apollo/client": "3.6.1",
"@babel/cli": "7.10.0",
"@babel/core": "7.20.2",
"@babel/plugin-proposal-object-rest-spread": "7.10.0",
"@babel/plugin-transform-flow-strip-types": "7.9.0",
"@babel/preset-env": "7.10.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": "11.3.0",
"apollo-upload-client": "17.0.0",
"bcrypt-nodejs": "0.0.3",
"clean-jsdoc-theme": "4.2.7",
"cross-env": "7.0.2",
"@actions/core": "1.11.1",
"@apollo/client": "3.13.8",
"@babel/cli": "7.27.0",
"@babel/core": "7.27.4",
"@babel/eslint-parser": "7.28.0",
"@babel/plugin-proposal-object-rest-spread": "7.20.7",
"@babel/plugin-transform-flow-strip-types": "7.26.5",
"@babel/preset-env": "7.27.2",
"@babel/preset-typescript": "7.27.1",
"@saithodev/semantic-release-backmerge": "4.0.1",
"@semantic-release/changelog": "6.0.3",
"@semantic-release/commit-analyzer": "13.0.1",
"@semantic-release/git": "10.0.1",
"@semantic-release/github": "11.0.2",
"@semantic-release/npm": "12.0.1",
"@semantic-release/release-notes-generator": "14.0.3",
"all-node-versions": "13.0.1",
"apollo-upload-client": "18.0.1",
"clean-jsdoc-theme": "4.3.0",
"cross-env": "7.0.3",
"deep-diff": "1.0.2",
"eslint": "8.26.0",
"eslint-plugin-flowtype": "8.0.3",
"flow-bin": "0.119.1",
"form-data": "3.0.0",
"eslint": "9.27.0",
"eslint-plugin-expect-type": "0.6.2",
"eslint-plugin-unused-imports": "4.3.0",
"form-data": "4.0.4",
"globals": "16.2.0",
"graphql-tag": "2.12.6",
"husky": "4.3.8",
"jasmine": "3.5.0",
"jasmine": "5.7.1",
"jasmine-spec-reporter": "7.0.0",
"jsdoc": "3.6.3",
"jsdoc": "4.0.4",
"jsdoc-babel": "0.5.0",
"lint-staged": "10.2.3",
"madge": "5.0.1",
"lint-staged": "16.1.0",
"m": "1.9.1",
"madge": "8.0.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-abort-controller": "3.0.1",
"mongodb-runner": "5.9.3",
"node-abort-controller": "3.1.1",
"node-fetch": "3.2.10",
"nyc": "15.1.0",
"nyc": "17.1.0",
"prettier": "2.0.5",
"semantic-release": "17.4.6",
"yaml": "1.10.0"
"semantic-release": "24.2.5",
"typescript": "5.8.3",
"typescript-eslint": "8.33.1",
"yaml": "2.8.0"
},
"scripts": {
"ci:check": "node ./ci/ciCheck.js",
@@ -113,38 +114,39 @@
"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",
"lint": "eslint --cache ./ --flag unstable_config_lookup_from_file",
"lint-fix": "eslint --fix --cache ./ --flag unstable_config_lookup_from_file",
"build": "babel src/ -d lib/ --copy-files --extensions '.ts,.js'",
"build:types": "tsc",
"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-runner start",
"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.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.3.2": "npm run test:mongodb --dbversion=5.3.2",
"test:mongodb:6.0.2": "npm run test:mongodb --dbversion=6.0.2",
"watch:ts": "tsc --watch",
"test:mongodb:6.0.19": "MONGODB_VERSION=6.0.19 npm run test",
"test:mongodb:7.0.16": "MONGODB_VERSION=7.0.16 npm run test",
"test:mongodb:8.0.4": "MONGODB_VERSION=8.0.4 npm run test",
"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",
"posttest:mongodb": "mongodb-runner stop",
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=6.0.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start",
"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.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner stop",
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 nyc jasmine",
"testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=8.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 jasmine",
"test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=8.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner exec -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017 -- npm run testonly",
"test:types": "eslint types/tests.ts -c ./types/eslint.config.mjs",
"coverage:mongodb": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=8.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner exec -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017 -- npm run coverage",
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=8.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 nyc jasmine",
"start": "node ./bin/parse-server",
"prettier": "prettier --write {src,spec}/{**/*,*}.js",
"prepare": "npm run build",
"postinstall": "node -p 'require(\"./postinstall.js\")()'",
"madge:circular": "node_modules/.bin/madge ./src --circular"
"madge:circular": "node_modules/.bin/madge ./src --circular",
"benchmark": "cross-env MONGODB_VERSION=8.0.4 MONGODB_TOPOLOGY=standalone mongodb-runner exec -t standalone --version 8.0.4 -- --port 27017 -- npm run benchmark:only",
"benchmark:only": "node benchmark/performance.js",
"benchmark:quick": "cross-env BENCHMARK_ITERATIONS=10 npm run benchmark:only"
},
"types": "types/index.d.ts",
"engines": {
"node": ">=14.21.0 <17 || >=18 <19"
"node": ">=18.20.4 <19.0.0 || >=20.18.0 <21.0.0 || >=22.12.0 <23.0.0 || >=24.11.0 <25.0.0"
},
"bin": {
"parse-server": "bin/parse-server"
},
"optionalDependencies": {
"@node-rs/bcrypt": "1.1.0"
"@node-rs/bcrypt": "1.10.7"
},
"collective": {
"type": "opencollective",
+34 -46
View File
@@ -1,50 +1,38 @@
const pkg = require('./package.json');
const message = `
1111111111
1111111111111111
1111111111111111111111
11111111111111111111111111
111111111111111 11111111
1111111111111 111 111111
1111111111111 111111111 111111
111111111111 11111111111 111111
1111111111111 11111111111 111111
1111111111111 1111111111 111111
1111111111111111111111111 1111111
11111111 11111111
111111 111 1111111111111111111
11111 11111 111111111111111111
11111 1 11111111111111111
111111 111111111111111111
11111111111111111111111111
1111111111111111111111
111111111111111111
11111111111
Thank you for using Parse Platform!
https://parseplatform.org
Please consider donating to help us maintain
this package:
const version = parseFloat(process.version.substring(1));
const minimum = parseFloat(pkg.engines.node.match(/\d+/g).join('.'));
👉 https://opencollective.com/parse-server 👈
module.exports = function () {
const openCollective = `
1111111111
1111111111111111
1111111111111111111111
11111111111111111111111111
111111111111111 11111111
1111111111111 111111
1111111111111 111111111 111111
111111111111 11111111111 111111
1111111111111 11111111111 111111
1111111111111 1111111111 111111
1111111111111111111111111 1111111
11111111 11111111
111111 1111111111111111111
11111 11111 111111111111111111
11111 11111111111111111
111111 111111111111111111
11111111111111111111111111
1111111111111111111111
111111111111111111
11111111111
`;
function main() {
process.stdout.write(message);
process.exit(0);
}
Thanks for installing parse 🙏
Please consider donating to our open collective
to help us maintain this package.
👉 https://opencollective.com/parse-server
`;
process.stdout.write(openCollective);
if (version >= minimum) {
process.exit(0);
}
const errorMessage = `
⚠️ parse-server requires at least node@${minimum}!
You have node@${version}
`;
process.stdout.write(errorMessage);
process.exit(1);
};
module.exports = main;
@@ -14,9 +14,9 @@
<body>
<h1>{{appName}}</h1>
<h1>Expired verification link!</h1>
<form method="POST" action="{{{publicServerUrl}}}/apps/{{{appId}}}/resend_verification_email">
<input name="username" type="hidden" value="{{{username}}}">
<input name="locale" type="hidden" value="{{{locale}}}">
<form method="POST" action="{{publicServerUrl}}/apps/{{appId}}/resend_verification_email">
<input name="token" type="hidden" value="{{token}}">
<input name="locale" type="hidden" value="{{locale}}">
<button type="submit">Resend Link</button>
</form>
</body>
+4 -4
View File
@@ -23,11 +23,11 @@
<p>You can set a new Password for your account: {{username}}</p>
<br />
<p>{{error}}</p>
<form id='form' action='{{{publicServerUrl}}}/apps/{{{appId}}}/request_password_reset' method='POST'>
<form id='form' action='{{publicServerUrl}}/apps/{{appId}}/request_password_reset' method='POST'>
<input name='utf-8' type='hidden' value='✓' />
<input name="username" type="hidden" id="username" value="{{{username}}}" />
<input name="token" type="hidden" id="token" value="{{{token}}}" />
<input name="locale" type="hidden" id="locale" value="{{{locale}}}" />
<input name="username" type="hidden" id="username" value="{{username}}" />
<input name="token" type="hidden" id="token" value="{{token}}" />
<input name="locale" type="hidden" id="locale" value="{{locale}}" />
<p>New Password</p>
<input name="new_password" type="password" id="password" />
@@ -14,9 +14,9 @@
<body>
<h1>{{appName}}</h1>
<h1>Expired verification link!</h1>
<form method="POST" action="{{{publicServerUrl}}}/apps/{{{appId}}}/resend_verification_email">
<input name="username" type="hidden" value="{{{username}}}">
<input name="locale" type="hidden" value="{{{locale}}}">
<form method="POST" action="{{publicServerUrl}}/apps/{{appId}}/resend_verification_email">
<input name="token" type="hidden" value="{{token}}">
<input name="locale" type="hidden" value="{{locale}}">
<button type="submit">Resend Link</button>
</form>
</body>
+4 -4
View File
@@ -23,11 +23,11 @@
<p>You can set a new Password for your account: {{username}}</p>
<br />
<p>{{error}}</p>
<form id='form' action='{{{publicServerUrl}}}/apps/{{{appId}}}/request_password_reset' method='POST'>
<form id='form' action='{{publicServerUrl}}/apps/{{appId}}/request_password_reset' method='POST'>
<input name='utf-8' type='hidden' value='✓' />
<input name="username" type="hidden" id="username" value="{{{username}}}" />
<input name="token" type="hidden" id="token" value="{{{token}}}" />
<input name="locale" type="hidden" id="locale" value="{{{locale}}}" />
<input name="username" type="hidden" id="username" value="{{username}}" />
<input name="token" type="hidden" id="token" value="{{token}}" />
<input name="locale" type="hidden" id="locale" value="{{locale}}" />
<p>New Password</p>
<input name="new_password" type="password" id="password" />
+3 -3
View File
@@ -14,9 +14,9 @@
<body>
<h1>{{appName}}</h1>
<h1>Expired verification link!</h1>
<form method="POST" action="{{{publicServerUrl}}}/apps/{{{appId}}}/resend_verification_email">
<input name="username" type="hidden" value="{{{username}}}">
<input name="locale" type="hidden" value="{{{locale}}}">
<form method="POST" action="{{publicServerUrl}}/apps/{{appId}}/resend_verification_email">
<input name="token" type="hidden" value="{{token}}">
<input name="locale" type="hidden" value="{{locale}}">
<button type="submit">Resend Link</button>
</form>
</body>
+4 -4
View File
@@ -23,11 +23,11 @@
<p>You can set a new Password for your account: {{username}}</p>
<br />
<p>{{error}}</p>
<form id='form' action='{{{publicServerUrl}}}/apps/{{{appId}}}/request_password_reset' method='POST'>
<form id='form' action='{{publicServerUrl}}/apps/{{appId}}/request_password_reset' method='POST'>
<input name='utf-8' type='hidden' value='✓' />
<input name="username" type="hidden" id="username" value="{{{username}}}" />
<input name="token" type="hidden" id="token" value="{{{token}}}" />
<input name="locale" type="hidden" id="locale" value="{{{locale}}}" />
<input name="username" type="hidden" id="username" value="{{username}}" />
<input name="token" type="hidden" id="token" value="{{token}}" />
<input name="locale" type="hidden" id="locale" value="{{locale}}" />
<p>New Password</p>
<input name="new_password" type="password" id="password" />
+3 -3
View File
@@ -47,8 +47,8 @@
window.onload = addDataToForm;
function addDataToForm() {
var username = getUrlParameter("username");
document.getElementById("usernameField").value = username;
const token = getUrlParameter("token");
document.getElementById("token").value = token;
var appId = getUrlParameter("appId");
document.getElementById("resendForm").action = '/apps/' + appId + '/resend_verification_email'
@@ -60,7 +60,7 @@
<div class="container">
<h1>Invalid Verification Link</h1>
<form id="resendForm" method="POST" action="/resend_verification_email">
<input id="usernameField" class="form-control" name="username" type="hidden" value="">
<input id="token" class="form-control" name="token" type="hidden" value="">
<button type="submit" class="btn btn-default">Resend Link</button>
</form>
</div>
+16 -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,20 +20,20 @@ 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"
+47 -12
View File
@@ -22,6 +22,7 @@ const nestedOptionTypes = [
'PagesOptions',
'PagesRoute',
'PasswordPolicyOptions',
'RequestComplexityOptions',
'SecurityOptions',
'SchemaOptions',
'LogLevels',
@@ -36,15 +37,18 @@ const nestedOptionEnvPrefix = {
IdempotencyOptions: 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_',
LiveQueryOptions: 'PARSE_SERVER_LIVEQUERY_',
LiveQueryServerOptions: 'PARSE_LIVE_QUERY_SERVER_',
LogClientEvent: 'PARSE_SERVER_DATABASE_LOG_CLIENT_EVENTS_',
LogLevel: 'PARSE_SERVER_LOG_LEVEL_',
LogLevels: 'PARSE_SERVER_LOG_LEVELS_',
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_',
RequestComplexityOptions: 'PARSE_SERVER_REQUEST_COMPLEXITY_',
SchemaOptions: 'PARSE_SERVER_SCHEMA_',
SecurityOptions: 'PARSE_SERVER_SECURITY_',
};
function last(array) {
@@ -153,6 +157,8 @@ function mapperFor(elt, t) {
return wrap(t.identifier('objectParser'));
} else if (t.isBooleanTypeAnnotation(elt)) {
return wrap(t.identifier('booleanParser'));
} else if (t.isObjectTypeAnnotation(elt)) {
return wrap(t.identifier('objectParser'));
} else if (t.isGenericTypeAnnotation(elt)) {
const type = elt.typeAnnotation.id.name;
if (type == 'Adapter') {
@@ -161,6 +167,9 @@ function mapperFor(elt, t) {
if (type == 'NumberOrBoolean') {
return wrap(t.identifier('numberOrBooleanParser'));
}
if (type == 'NumberOrString') {
return t.callExpression(wrap(t.identifier('numberOrStringParser')), [t.stringLiteral(elt.name)]);
}
if (type === 'StringOrStringArray') {
return wrap(t.identifier('arrayParser'));
}
@@ -212,6 +221,9 @@ function parseDefaultValue(elt, value, t) {
if (type == 'NumberOrBoolean') {
literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value));
}
if (type == 'NumberOrString') {
literalValue = t.numericLiteral(parsers.numberOrStringParser('')(value));
}
if (nestedOptionTypes.includes(type)) {
const object = parsers.objectParser(value);
@@ -254,6 +266,23 @@ function inject(t, list) {
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) {
@@ -347,12 +376,18 @@ 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,
});
require('fs').writeFileSync('./src/Options/Definitions.js', res.code + '\n');
require('fs').writeFileSync('./src/Options/docs.js', docs);
// Only run the transformation when executed directly, not when imported by tests
if (require.main === module) {
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);
}
// Export mapperFor for testing
module.exports = { mapperFor };
+3 -3
View File
@@ -3,12 +3,12 @@
"@babel/plugin-proposal-object-rest-spread"
],
"presets": [
"@babel/preset-typescript",
["@babel/preset-env", {
"targets": {
"node": "14"
"node": "18"
}
}]
],
"sourceMaps": "inline",
"retainLines": true
"sourceMaps": "inline"
}
-45
View File
@@ -1,45 +0,0 @@
{
"env": {
"jasmine": true
},
"globals": {
"Parse": true,
"reconfigureServer": true,
"createTestUser": true,
"jfail": true,
"ok": true,
"strictEqual": true,
"TestObject": true,
"Item": true,
"Container": true,
"equal": true,
"expectAsync": true,
"notEqual": true,
"it_id": true,
"it_only_db": true,
"it_only_mongodb_version": true,
"it_only_postgres_version": true,
"it_only_node_version": true,
"fit_only_mongodb_version": true,
"fit_only_node_version": true,
"it_exclude_mongodb_version": true,
"it_exclude_postgres_version": true,
"fit_exclude_mongodb_version": true,
"fit_exclude_node_version": true,
"it_exclude_dbs": true,
"describe_only_db": true,
"describe_only": true,
"on_db": true,
"defaultConfiguration": true,
"range": true,
"jequal": true,
"create": true,
"arrayContains": true,
"databaseAdapter": true,
"databaseURI": true
},
"rules": {
"no-console": [0],
"no-var": "error"
}
}
+2 -2
View File
@@ -419,7 +419,7 @@ describe('lockout with password reset option', () => {
await request({
method: 'POST',
url: `${config.publicServerURL}/apps/test/request_password_reset`,
body: `new_password=${newPassword}&token=${token}&username=${username}`,
body: `new_password=${newPassword}&token=${token}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
@@ -454,7 +454,7 @@ describe('lockout with password reset option', () => {
await request({
method: 'POST',
url: `${config.publicServerURL}/apps/test/request_password_reset`,
body: `new_password=${newPassword}&token=${token}&username=${username}`,
body: `new_password=${newPassword}&token=${token}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
+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');
+182
View File
@@ -0,0 +1,182 @@
const BaseAuthCodeAdapter = require('../../../lib/Adapters/Auth/BaseCodeAuthAdapter').default;
describe('BaseAuthCodeAdapter', function () {
let adapter;
const adapterName = 'TestAdapter';
const validOptions = {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
};
class TestAuthCodeAdapter extends BaseAuthCodeAdapter {
async getUserFromAccessToken(accessToken) {
if (accessToken === 'validAccessToken') {
return { id: 'validUserId' };
}
throw new Error('Invalid access token');
}
async getAccessTokenFromCode(authData) {
if (authData.code === 'validCode') {
return 'validAccessToken';
}
throw new Error('Invalid code');
}
}
beforeEach(function () {
adapter = new TestAuthCodeAdapter(adapterName);
});
describe('validateOptions', function () {
it('should throw error if options are missing', function () {
expect(() => adapter.validateOptions(null)).toThrowError(`${adapterName} options are required.`);
});
it('should throw error if clientId is missing in secure mode', function () {
expect(() =>
adapter.validateOptions({ clientSecret: 'validClientSecret' })
).toThrowError(`${adapterName} clientId is required.`);
});
it('should throw error if clientSecret is missing in secure mode', function () {
expect(() =>
adapter.validateOptions({ clientId: 'validClientId' })
).toThrowError(`${adapterName} clientSecret is required.`);
});
it('should not throw error for valid options', function () {
expect(() => adapter.validateOptions(validOptions)).not.toThrow();
expect(adapter.clientId).toBe('validClientId');
expect(adapter.clientSecret).toBe('validClientSecret');
expect(adapter.enableInsecureAuth).toBeUndefined();
});
it('should allow insecure mode without clientId or clientSecret', function () {
const options = { enableInsecureAuth: true };
expect(() => adapter.validateOptions(options)).not.toThrow();
expect(adapter.enableInsecureAuth).toBe(true);
});
});
describe('beforeFind', function () {
it('should throw error if code is missing in secure mode', async function () {
adapter.validateOptions(validOptions);
const authData = { access_token: 'validAccessToken' };
await expectAsync(adapter.beforeFind(authData)).toBeRejectedWithError(
`${adapterName} code is required.`
);
});
it('should throw error if access token is missing in insecure mode', async function () {
adapter.validateOptions({ enableInsecureAuth: true });
const authData = {};
await expectAsync(adapter.beforeFind(authData)).toBeRejectedWithError(
`${adapterName} auth is invalid for this user.`
);
});
it('should throw error if user ID does not match in insecure mode', async function () {
adapter.validateOptions({ enableInsecureAuth: true });
const authData = { id: 'invalidUserId', access_token: 'validAccessToken' };
await expectAsync(adapter.beforeFind(authData)).toBeRejectedWithError(
`${adapterName} auth is invalid for this user.`
);
});
it('should process valid secure payload and update authData', async function () {
adapter.validateOptions(validOptions);
const authData = { code: 'validCode' };
await adapter.beforeFind(authData);
expect(authData.access_token).toBe('validAccessToken');
expect(authData.id).toBe('validUserId');
expect(authData.code).toBeUndefined();
});
it('should process valid insecure payload', async function () {
adapter.validateOptions({ enableInsecureAuth: true });
const authData = { id: 'validUserId', access_token: 'validAccessToken' };
await expectAsync(adapter.beforeFind(authData)).toBeResolved();
});
});
describe('getUserFromAccessToken', function () {
it('should throw error if not implemented in base class', async function () {
const baseAdapter = new BaseAuthCodeAdapter(adapterName);
await expectAsync(baseAdapter.getUserFromAccessToken('test')).toBeRejectedWithError(
'getUserFromAccessToken is not implemented'
);
});
it('should return valid user for valid access token', async function () {
const user = await adapter.getUserFromAccessToken('validAccessToken', {});
expect(user).toEqual({ id: 'validUserId' });
});
it('should throw error for invalid access token', async function () {
await expectAsync(adapter.getUserFromAccessToken('invalidAccessToken', {})).toBeRejectedWithError(
'Invalid access token'
);
});
});
describe('getAccessTokenFromCode', function () {
it('should throw error if not implemented in base class', async function () {
const baseAdapter = new BaseAuthCodeAdapter(adapterName);
await expectAsync(baseAdapter.getAccessTokenFromCode({ code: 'test' })).toBeRejectedWithError(
'getAccessTokenFromCode is not implemented'
);
});
it('should return valid access token for valid code', async function () {
const accessToken = await adapter.getAccessTokenFromCode({ code: 'validCode' });
expect(accessToken).toBe('validAccessToken');
});
it('should throw error for invalid code', async function () {
await expectAsync(adapter.getAccessTokenFromCode({ code: 'invalidCode' })).toBeRejectedWithError(
'Invalid code'
);
});
});
describe('validateLogin', function () {
it('should return user id from authData', function () {
const authData = { id: 'validUserId' };
const result = adapter.validateLogin(authData);
expect(result).toEqual({ id: 'validUserId' });
});
});
describe('validateSetUp', function () {
it('should return user id from authData', function () {
const authData = { id: 'validUserId' };
const result = adapter.validateSetUp(authData);
expect(result).toEqual({ id: 'validUserId' });
});
});
describe('afterFind', function () {
it('should return user id from authData', function () {
const authData = { id: 'validUserId' };
const result = adapter.afterFind(authData);
expect(result).toEqual({ id: 'validUserId' });
});
});
describe('validateUpdate', function () {
it('should return user id from authData', function () {
const authData = { id: 'validUserId' };
const result = adapter.validateUpdate(authData);
expect(result).toEqual({ id: 'validUserId' });
});
});
});
+220
View File
@@ -0,0 +1,220 @@
const GameCenterAuth = require('../../../lib/Adapters/Auth/gcenter').default;
const { pki } = require('node-forge');
const fs = require('fs');
const path = require('path');
describe('GameCenterAuth Adapter', function () {
let adapter;
beforeEach(function () {
adapter = new GameCenterAuth.constructor();
const gcProd4 = fs.readFileSync(path.resolve(__dirname, '../../support/cert/gc-prod-4.cer'));
const digicertPem = fs.readFileSync(path.resolve(__dirname, '../../support/cert/DigiCertTrustedG4CodeSigningRSA4096SHA3842021CA1.crt.pem')).toString();
mockFetch([
{
url: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
method: 'GET',
response: {
ok: true,
headers: new Map(),
arrayBuffer: () => Promise.resolve(
gcProd4.buffer.slice(gcProd4.byteOffset, gcProd4.byteOffset + gcProd4.length)
),
},
},
{
url: 'https://cacerts.digicert.com/DigiCertTrustedG4CodeSigningRSA4096SHA3842021CA1.crt.pem',
method: 'GET',
response: {
ok: true,
headers: new Map([['content-type', 'application/x-pem-file'], ['content-length', digicertPem.length.toString()]]),
text: () => Promise.resolve(digicertPem),
},
}
]);
});
describe('Test config failing due to missing params or wrong types', function () {
it('should throw error for invalid options', async function () {
const invalidOptions = [
null,
undefined,
{},
{ bundleId: '' },
{ enableInsecureAuth: false }, // Missing bundleId in secure mode
];
for (const options of invalidOptions) {
expect(() => adapter.validateOptions(options)).withContext(JSON.stringify(options)).toThrow()
}
});
it('should validate options successfully with valid parameters', function () {
const validOptions = { bundleId: 'com.valid.app', enableInsecureAuth: false };
expect(() => adapter.validateOptions(validOptions)).not.toThrow();
});
});
describe('Test payload failing due to missing params or wrong types', function () {
it('should throw error for missing authData fields', async function () {
await expectAsync(adapter.validateAuthData({})).toBeRejectedWithError(
'AuthData id is missing.'
);
});
});
describe('Test payload fails due to incorrect appId / certificate', function () {
it('should throw error for invalid publicKeyUrl', async function () {
const invalidPublicKeyUrl = 'https://malicious.url.com/key.cer';
spyOn(adapter, 'fetchCertificate').and.throwError(
new Error('Invalid publicKeyUrl')
);
await expectAsync(
adapter.getAppleCertificate(invalidPublicKeyUrl)
).toBeRejectedWithError('Invalid publicKeyUrl: https://malicious.url.com/key.cer');
});
it('should throw error for invalid signature verification', async function () {
const fakePublicKey = 'invalid-key';
const fakeAuthData = {
id: '1234567',
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1460981421303,
salt: 'saltST==',
signature: 'invalidSignature',
};
spyOn(adapter, 'getAppleCertificate').and.returnValue(Promise.resolve(fakePublicKey));
spyOn(adapter, 'verifySignature').and.throwError('Invalid signature.');
await expectAsync(adapter.validateAuthData(fakeAuthData)).toBeRejectedWithError(
'Invalid signature.'
);
});
});
describe('Test payload passing', function () {
it('should successfully process valid payload and save auth data', async function () {
const validAuthData = {
id: '1234567',
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1460981421303,
salt: 'saltST==',
signature: 'validSignature',
bundleId: 'com.valid.app',
};
spyOn(adapter, 'getAppleCertificate').and.returnValue(Promise.resolve('validKey'));
spyOn(adapter, 'verifySignature').and.returnValue(true);
await expectAsync(adapter.validateAuthData(validAuthData)).toBeResolved();
});
});
describe('Certificate and Signature Validation', function () {
it('should fetch and validate Apple certificate', async function () {
const certUrl = 'https://static.gc.apple.com/public-key/gc-prod-4.cer';
const mockCertificate = 'mockCertificate';
spyOn(adapter, 'fetchCertificate').and.returnValue(
Promise.resolve({ certificate: mockCertificate, headers: new Map() })
);
spyOn(pki, 'certificateFromPem').and.returnValue({});
adapter.cache[certUrl] = mockCertificate;
const cert = await adapter.getAppleCertificate(certUrl);
expect(cert).toBe(mockCertificate);
});
it('should verify signature successfully', async function () {
const authData = {
id: 'G:1965586982',
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1565257031287,
signature:
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
salt: 'DzqqrQ==',
};
adapter.bundleId = 'cloud.xtralife.gamecenterauth';
adapter.enableInsecureAuth = false;
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
});
it('should not use bundle id from authData payload in secure mode', async function () {
const authData = {
id: 'G:1965586982',
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1565257031287,
signature:
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
salt: 'DzqqrQ==',
bundleId: 'com.example.insecure.app',
};
adapter.bundleId = 'cloud.xtralife.gamecenterauth';
adapter.enableInsecureAuth = false;
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
});
it('should not use bundle id from authData payload in insecure mode', async function () {
const authData = {
id: 'G:1965586982',
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1565257031287,
signature:
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
salt: 'DzqqrQ==',
bundleId: 'com.example.insecure.app',
};
adapter.bundleId = 'cloud.xtralife.gamecenterauth';
adapter.enableInsecureAuth = true;
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
});
it('can use bundle id from authData payload in insecure mode', async function () {
const authData = {
id: 'G:1965586982',
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
timestamp: 1565257031287,
signature:
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
salt: 'DzqqrQ==',
bundleId: 'cloud.xtralife.gamecenterauth',
};
adapter.enableInsecureAuth = true;
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
});
});
});
+285
View File
@@ -0,0 +1,285 @@
const GitHubAdapter = require('../../../lib/Adapters/Auth/github').default;
describe('GitHubAdapter', function () {
let adapter;
const validOptions = {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
};
beforeEach(function () {
adapter = new GitHubAdapter.constructor();
adapter.validateOptions(validOptions);
});
describe('getAccessTokenFromCode', function () {
it('should fetch an access token successfully', async function () {
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken',
}),
},
},
]);
const code = 'validCode';
const token = await adapter.getAccessTokenFromCode(code);
expect(token).toBe('mockAccessToken');
});
it('should throw an error if the response is not ok', async function () {
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: false,
statusText: 'Bad Request',
},
},
]);
const code = 'invalidCode';
await expectAsync(adapter.getAccessTokenFromCode(code)).toBeRejectedWithError(
'Failed to exchange code for token: Bad Request'
);
});
it('should throw an error if the response contains an error', async function () {
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
error: 'invalid_grant',
error_description: 'Code is invalid',
}),
},
},
]);
const code = 'invalidCode';
await expectAsync(adapter.getAccessTokenFromCode(code)).toBeRejectedWithError('Code is invalid');
});
});
describe('getUserFromAccessToken', function () {
it('should fetch user data successfully', async function () {
mockFetch([
{
url: 'https://api.github.com/user',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
login: 'mockUserLogin',
}),
},
},
]);
const accessToken = 'validAccessToken';
const user = await adapter.getUserFromAccessToken(accessToken);
expect(user).toEqual({ id: 'mockUserId', login: 'mockUserLogin' });
});
it('should throw an error if the response is not ok', async function () {
mockFetch([
{
url: 'https://api.github.com/user',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const accessToken = 'invalidAccessToken';
await expectAsync(adapter.getUserFromAccessToken(accessToken)).toBeRejectedWithError(
'Failed to fetch GitHub user: Unauthorized'
);
});
it('should throw an error if user data is invalid', async function () {
mockFetch([
{
url: 'https://api.github.com/user',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({}),
},
},
]);
const accessToken = 'validAccessToken';
await expectAsync(adapter.getUserFromAccessToken(accessToken)).toBeRejectedWithError(
'Invalid GitHub user data received.'
);
});
});
describe('GitHubAdapter E2E Test', function () {
beforeEach(async function () {
await reconfigureServer({
auth: {
github: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
},
},
});
});
it('should log in user using GitHub adapter successfully', async function () {
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.github.com/user',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
login: 'mockUserLogin',
}),
},
},
]);
const authData = { code: 'validCode' };
const user = await Parse.User.logInWith('github', { authData });
expect(user.id).toBeDefined();
});
it('should handle error when GitHub returns invalid code', async function () {
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: false,
statusText: 'Invalid code',
},
},
]);
const authData = { code: 'invalidCode' };
await expectAsync(Parse.User.logInWith('github', { authData })).toBeRejectedWithError(
'Failed to exchange code for token: Invalid code'
);
});
it('should handle error when GitHub returns invalid user data', async function () {
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.github.com/user',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const authData = { code: 'validCode' };
await expectAsync(Parse.User.logInWith('github', { authData })).toBeRejectedWithError(
'Failed to fetch GitHub user: Unauthorized'
);
});
it('e2e secure does not support insecure payload', async function () {
mockFetch();
const authData = { id: 'mockUserId', access_token: 'mockAccessToken123' };
await expectAsync(Parse.User.logInWith('github', { authData })).toBeRejectedWithError(
'GitHub code is required.'
);
});
it('e2e insecure does support secure payload', async function () {
await reconfigureServer({
auth: {
github: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: true,
},
},
});
mockFetch([
{
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.github.com/user',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
login: 'mockUserLogin',
}),
},
},
]);
const authData = { code: 'validCode' };
const user = await Parse.User.logInWith('github', { authData });
expect(user.id).toBeDefined();
});
});
});
+356
View File
@@ -0,0 +1,356 @@
const GooglePlayGamesServicesAdapter = require('../../../lib/Adapters/Auth/gpgames').default;
describe('GooglePlayGamesServicesAdapter', function () {
let adapter;
beforeEach(function () {
adapter = new GooglePlayGamesServicesAdapter.constructor();
adapter.clientId = 'validClientId';
adapter.clientSecret = 'validClientSecret';
});
describe('getAccessTokenFromCode', function () {
it('should fetch an access token successfully', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken',
}),
},
},
]);
const code = 'validCode';
const authData = { redirectUri: 'http://example.com' };
const token = await adapter.getAccessTokenFromCode(code, authData);
expect(token).toBe('mockAccessToken');
});
it('should throw an error if the response is not ok', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: false,
statusText: 'Bad Request',
},
},
]);
const code = 'invalidCode';
const authData = { redirectUri: 'http://example.com' };
await expectAsync(adapter.getAccessTokenFromCode(code, authData)).toBeRejectedWithError(
'Failed to exchange code for token: Bad Request'
);
});
it('should throw an error if the response contains an error', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
error: 'invalid_grant',
error_description: 'Code is invalid',
}),
},
},
]);
const code = 'invalidCode';
const authData = { redirectUri: 'http://example.com' };
await expectAsync(adapter.getAccessTokenFromCode(code, authData)).toBeRejectedWithError(
'Code is invalid'
);
});
});
describe('getUserFromAccessToken', function () {
it('should fetch user data successfully', async function () {
mockFetch([
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
playerId: 'mockUserId',
}),
},
},
]);
const accessToken = 'validAccessToken';
const authData = { id: 'mockUserId' };
const user = await adapter.getUserFromAccessToken(accessToken, authData);
expect(user).toEqual({ id: 'mockUserId' });
});
it('should throw an error if the response is not ok', async function () {
mockFetch([
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const accessToken = 'invalidAccessToken';
const authData = { id: 'mockUserId' };
await expectAsync(adapter.getUserFromAccessToken(accessToken, authData)).toBeRejectedWithError(
'Failed to fetch Google Play Games Services user: Unauthorized'
);
});
it('should throw an error if user data is invalid', async function () {
mockFetch([
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({}),
},
},
]);
const accessToken = 'validAccessToken';
const authData = { id: 'mockUserId' };
await expectAsync(adapter.getUserFromAccessToken(accessToken, authData)).toBeRejectedWithError(
'Invalid Google Play Games Services user data received.'
);
});
it('should throw an error if playerId does not match the provided user ID', async function () {
mockFetch([
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
playerId: 'anotherUserId',
}),
},
},
]);
const accessToken = 'validAccessToken';
const authData = { id: 'mockUserId' };
await expectAsync(adapter.getUserFromAccessToken(accessToken, authData)).toBeRejectedWithError(
'Invalid Google Play Games Services user data received.'
);
});
});
describe('GooglePlayGamesServicesAdapter E2E Test', function () {
beforeEach(async function () {
await reconfigureServer({
auth: {
gpgames: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
},
},
});
});
it('should log in user successfully with valid code', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
playerId: 'mockUserId',
}),
},
},
]);
const authData = {
code: 'validCode',
id: 'mockUserId',
redirectUri: 'http://example.com',
};
const user = await Parse.User.logInWith('gpgames', { authData });
expect(user.id).toBeDefined();
expect(global.fetch).toHaveBeenCalledWith(
'https://oauth2.googleapis.com/token',
jasmine.any(Object)
);
expect(global.fetch).toHaveBeenCalledWith(
'https://www.googleapis.com/games/v1/players/mockUserId',
jasmine.any(Object)
);
});
it('should handle error when the token exchange fails', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: false,
statusText: 'Invalid code',
},
},
]);
const authData = {
code: 'invalidCode',
redirectUri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('gpgames', { authData })).toBeRejectedWithError(
'Failed to exchange code for token: Invalid code'
);
expect(global.fetch).toHaveBeenCalledWith(
'https://oauth2.googleapis.com/token',
jasmine.any(Object)
);
});
it('should handle error when user data fetch fails', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const authData = {
code: 'validCode',
id: 'mockUserId',
redirectUri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('gpgames', { authData })).toBeRejectedWithError(
'Failed to fetch Google Play Games Services user: Unauthorized'
);
expect(global.fetch).toHaveBeenCalledWith(
'https://oauth2.googleapis.com/token',
jasmine.any(Object)
);
expect(global.fetch).toHaveBeenCalledWith(
'https://www.googleapis.com/games/v1/players/mockUserId',
jasmine.any(Object)
);
});
it('should handle error when user data is invalid', async function () {
mockFetch([
{
url: 'https://oauth2.googleapis.com/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://www.googleapis.com/games/v1/players/mockUserId',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
playerId: 'anotherUserId',
}),
},
},
]);
const authData = {
code: 'validCode',
id: 'mockUserId',
redirectUri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('gpgames', { authData })).toBeRejectedWithError(
'Invalid Google Play Games Services user data received.'
);
expect(global.fetch).toHaveBeenCalledWith(
'https://oauth2.googleapis.com/token',
jasmine.any(Object)
);
expect(global.fetch).toHaveBeenCalledWith(
'https://www.googleapis.com/games/v1/players/mockUserId',
jasmine.any(Object)
);
});
it('should handle error when no code or access token is provided', async function () {
mockFetch();
const authData = {
id: 'mockUserId',
};
await expectAsync(Parse.User.logInWith('gpgames', { authData })).toBeRejectedWithError(
'gpgames code is required.'
);
expect(global.fetch).not.toHaveBeenCalled();
});
});
});
+283
View File
@@ -0,0 +1,283 @@
const InstagramAdapter = require('../../../lib/Adapters/Auth/instagram').default;
describe('InstagramAdapter', function () {
let adapter;
beforeEach(function () {
adapter = new InstagramAdapter.constructor();
adapter.clientId = 'validClientId';
adapter.clientSecret = 'validClientSecret';
adapter.redirectUri = 'https://example.com/callback';
});
describe('getAccessTokenFromCode', function () {
it('should fetch an access token successfully', async function () {
mockFetch([
{
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken',
}),
},
},
]);
const authData = { code: 'validCode' };
const token = await adapter.getAccessTokenFromCode(authData);
expect(token).toBe('mockAccessToken');
});
it('should throw an error if the response contains an error', async function () {
mockFetch([
{
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
error: 'invalid_grant',
error_description: 'Code is invalid',
}),
},
},
]);
const authData = { code: 'invalidCode' };
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWithError(
'Code is invalid'
);
});
});
describe('getUserFromAccessToken', function () {
it('should fetch user data successfully', async function () {
mockFetch([
{
url: 'https://graph.instagram.com/me?fields=id&access_token=mockAccessToken',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
}),
},
},
]);
const accessToken = 'mockAccessToken';
const authData = { id: 'mockUserId' };
const user = await adapter.getUserFromAccessToken(accessToken, authData);
expect(user).toEqual({ id: 'mockUserId' });
});
it('should throw an error if user ID does not match authData', async function () {
mockFetch([
{
url: 'https://graph.instagram.com/me?fields=id&access_token=mockAccessToken',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'differentUserId',
}),
},
},
]);
const accessToken = 'mockAccessToken';
const authData = { id: 'mockUserId' };
await expectAsync(adapter.getUserFromAccessToken(accessToken, authData)).toBeRejectedWithError(
'Instagram auth is invalid for this user.'
);
});
it('should ignore client-provided apiURL and use hardcoded endpoint', async () => {
const accessToken = 'mockAccessToken';
const authData = {
id: 'mockUserId',
apiURL: 'https://example.com/',
};
mockFetch([
{
url: 'https://graph.instagram.com/me?fields=id&access_token=mockAccessToken',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
}),
},
},
]);
const user = await adapter.getUserFromAccessToken(accessToken, authData);
expect(user).toEqual({ id: 'mockUserId' });
});
});
describe('InstagramAdapter E2E Test', function () {
beforeEach(async function () {
await reconfigureServer({
auth: {
instagram: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
redirectUri: 'https://example.com/callback',
},
},
});
});
it('should log in user successfully with valid code', async function () {
mockFetch([
{
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://graph.instagram.com/me?fields=id&access_token=mockAccessToken123',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
}),
},
},
]);
const authData = {
code: 'validCode',
id: 'mockUserId',
};
const user = await Parse.User.logInWith('instagram', { authData });
expect(user.id).toBeDefined();
});
it('should handle error when access token exchange fails', async function () {
mockFetch([
{
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
response: {
ok: false,
statusText: 'Invalid code',
},
},
]);
const authData = {
code: 'invalidCode',
};
await expectAsync(Parse.User.logInWith('instagram', { authData })).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Instagram API request failed.')
);
});
it('should handle error when user data fetch fails', async function () {
mockFetch([
{
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://graph.instagram.com/me?fields=id&access_token=mockAccessToken123',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const authData = {
code: 'validCode',
id: 'mockUserId',
};
await expectAsync(Parse.User.logInWith('instagram', { authData })).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Instagram API request failed.')
);
});
it('should handle error when user data is invalid', async function () {
mockFetch([
{
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://graph.instagram.com/me?fields=id&access_token=mockAccessToken123',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'differentUserId',
}),
},
},
]);
const authData = {
code: 'validCode',
id: 'mockUserId',
};
await expectAsync(Parse.User.logInWith('instagram', { authData })).toBeRejectedWithError(
'Instagram auth is invalid for this user.'
);
});
it('should handle error when no code or access token is provided', async function () {
mockFetch();
const authData = {
id: 'mockUserId',
};
await expectAsync(Parse.User.logInWith('instagram', { authData })).toBeRejectedWithError(
'Instagram code is required.'
);
});
});
});
+309
View File
@@ -0,0 +1,309 @@
const LineAdapter = require('../../../lib/Adapters/Auth/line').default;
describe('LineAdapter', function () {
let adapter;
beforeEach(function () {
adapter = new LineAdapter.constructor();
adapter.clientId = 'validClientId';
adapter.clientSecret = 'validClientSecret';
});
describe('getAccessTokenFromCode', function () {
it('should throw an error if code is missing in authData', async function () {
const authData = { redirect_uri: 'http://example.com' };
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWithError(
'Line auth is invalid for this user.'
);
});
it('should fetch an access token successfully', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken',
}),
},
},
]);
const authData = {
code: 'validCode',
redirect_uri: 'http://example.com',
};
const token = await adapter.getAccessTokenFromCode(authData);
expect(token).toBe('mockAccessToken');
});
it('should throw an error if response is not ok', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: false,
statusText: 'Bad Request',
},
},
]);
const authData = {
code: 'invalidCode',
redirect_uri: 'http://example.com',
};
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWithError(
'Failed to exchange code for token: Bad Request'
);
});
it('should throw an error if response contains an error object', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
error: 'invalid_grant',
error_description: 'Code is invalid',
}),
},
},
]);
const authData = {
code: 'invalidCode',
redirect_uri: 'http://example.com',
};
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWithError(
'Code is invalid'
);
});
});
describe('getUserFromAccessToken', function () {
it('should fetch user data successfully', async function () {
mockFetch([
{
url: 'https://api.line.me/v2/profile',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
userId: 'mockUserId',
displayName: 'mockDisplayName',
}),
},
},
]);
const accessToken = 'validAccessToken';
const user = await adapter.getUserFromAccessToken(accessToken);
expect(user).toEqual({
userId: 'mockUserId',
displayName: 'mockDisplayName',
});
});
it('should throw an error if response is not ok', async function () {
mockFetch([
{
url: 'https://api.line.me/v2/profile',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const accessToken = 'invalidAccessToken';
await expectAsync(adapter.getUserFromAccessToken(accessToken)).toBeRejectedWithError(
'Failed to fetch Line user: Unauthorized'
);
});
it('should throw an error if user data is invalid', async function () {
mockFetch([
{
url: 'https://api.line.me/v2/profile',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({}),
},
},
]);
const accessToken = 'validAccessToken';
await expectAsync(adapter.getUserFromAccessToken(accessToken)).toBeRejectedWithError(
'Invalid Line user data received.'
);
});
});
describe('LineAdapter E2E Test', function () {
beforeEach(async function () {
await reconfigureServer({
auth: {
line: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
},
},
});
});
it('should log in user successfully with valid code', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.line.me/v2/profile',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
userId: 'mockUserId',
displayName: 'mockDisplayName',
}),
},
},
]);
const authData = {
code: 'validCode',
redirect_uri: 'http://example.com',
};
const user = await Parse.User.logInWith('line', { authData });
expect(user.id).toBeDefined();
});
it('should handle error when token exchange fails', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: false,
statusText: 'Invalid code',
},
},
]);
const authData = {
code: 'invalidCode',
redirect_uri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('line', { authData })).toBeRejectedWithError(
'Failed to exchange code for token: Invalid code'
);
});
it('should handle error when user data fetch fails', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.line.me/v2/profile',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const authData = {
code: 'validCode',
redirect_uri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('line', { authData })).toBeRejectedWithError(
'Failed to fetch Line user: Unauthorized'
);
});
it('should handle error when user data is invalid', async function () {
mockFetch([
{
url: 'https://api.line.me/oauth2/v2.1/token',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.line.me/v2/profile',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({}),
},
},
]);
const authData = {
code: 'validCode',
redirect_uri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('line', { authData })).toBeRejectedWithError(
'Invalid Line user data received.'
);
});
it('should handle error when no code is provided', async function () {
mockFetch();
const authData = {
redirect_uri: 'http://example.com',
};
await expectAsync(Parse.User.logInWith('line', { authData })).toBeRejectedWithError(
'Line code is required.'
);
});
});
});
+333
View File
@@ -0,0 +1,333 @@
const LinkedInAdapter = require('../../../lib/Adapters/Auth/linkedin').default;
describe('LinkedInAdapter', function () {
let adapter;
const validOptions = {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: false,
};
beforeEach(function () {
adapter = new LinkedInAdapter.constructor();
});
describe('Test configuration errors', function () {
it('should throw error for missing options', function () {
const invalidOptions = [null, undefined, {}, { clientId: 'validClientId' }];
for (const options of invalidOptions) {
expect(() => {
adapter.validateOptions(options);
}).toThrow();
}
});
it('should validate options successfully with valid parameters', function () {
expect(() => {
adapter.validateOptions(validOptions);
}).not.toThrow();
expect(adapter.clientId).toBe(validOptions.clientId);
expect(adapter.clientSecret).toBe(validOptions.clientSecret);
expect(adapter.enableInsecureAuth).toBe(validOptions.enableInsecureAuth);
});
});
describe('Test beforeFind', function () {
it('should throw error for invalid payload', async function () {
adapter.enableInsecureAuth = true;
const payloads = [{}, { access_token: null }];
for (const payload of payloads) {
await expectAsync(adapter.beforeFind(payload)).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LinkedIn auth is invalid for this user.')
);
}
});
it('should process secure payload and set auth data', async function () {
spyOn(adapter, 'getAccessTokenFromCode').and.returnValue(
Promise.resolve('validToken')
);
spyOn(adapter, 'getUserFromAccessToken').and.returnValue(
Promise.resolve({ id: 'validUserId' })
);
const authData = { code: 'validCode', redirect_uri: 'http://example.com', is_mobile_sdk: false };
await adapter.beforeFind(authData);
expect(authData.access_token).toBe('validToken');
expect(authData.id).toBe('validUserId');
});
it('should validate insecure auth and match user id', async function () {
adapter.enableInsecureAuth = true;
spyOn(adapter, 'getUserFromAccessToken').and.returnValue(
Promise.resolve({ id: 'validUserId' })
);
const authData = { access_token: 'validToken', id: 'validUserId', is_mobile_sdk: false };
await expectAsync(adapter.beforeFind(authData)).toBeResolved();
});
it('should throw error if insecure auth user id does not match', async function () {
adapter.enableInsecureAuth = true;
spyOn(adapter, 'getUserFromAccessToken').and.returnValue(
Promise.resolve({ id: 'invalidUserId' })
);
const authData = { access_token: 'validToken', id: 'validUserId', is_mobile_sdk: false };
await expectAsync(adapter.beforeFind(authData)).toBeRejectedWith(
new Error('LinkedIn auth is invalid for this user.')
);
});
});
describe('Test getUserFromAccessToken', function () {
it('should fetch user successfully', async function () {
mockFetch([
{
url: 'https://api.linkedin.com/v2/me',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ id: 'validUserId' }),
},
},
]);
const user = await adapter.getUserFromAccessToken('validToken', false);
expect(global.fetch).toHaveBeenCalledWith('https://api.linkedin.com/v2/me', {
headers: {
Authorization: `Bearer validToken`,
'x-li-format': 'json',
'x-li-src': undefined,
},
method: 'GET',
});
expect(user).toEqual({ id: 'validUserId' });
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://api.linkedin.com/v2/me',
method: 'GET',
response: {
ok: false,
},
},
]);
await expectAsync(adapter.getUserFromAccessToken('invalidToken', false)).toBeRejectedWith(
new Error('LinkedIn API request failed.')
);
});
});
describe('Test getAccessTokenFromCode', function () {
it('should fetch token successfully', async function () {
mockFetch([
{
url: 'https://www.linkedin.com/oauth/v2/accessToken',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validToken' }),
},
},
]);
const tokenResponse = await adapter.getAccessTokenFromCode('validCode', 'http://example.com');
expect(global.fetch).toHaveBeenCalledWith('https://www.linkedin.com/oauth/v2/accessToken', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: jasmine.any(URLSearchParams),
});
expect(tokenResponse).toEqual('validToken');
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://www.linkedin.com/oauth/v2/accessToken',
method: 'POST',
response: {
ok: false,
},
},
]);
await expectAsync(
adapter.getAccessTokenFromCode('invalidCode', 'http://example.com')
).toBeRejectedWith(new Error('LinkedIn API request failed.'));
});
});
describe('Test validate methods', function () {
const authData = { id: 'validUserId', access_token: 'validToken' };
it('validateLogin should return user id', function () {
const result = adapter.validateLogin(authData);
expect(result).toEqual({ id: 'validUserId' });
});
it('validateSetUp should return user id', function () {
const result = adapter.validateSetUp(authData);
expect(result).toEqual({ id: 'validUserId' });
});
it('validateUpdate should return user id', function () {
const result = adapter.validateUpdate(authData);
expect(result).toEqual({ id: 'validUserId' });
});
it('afterFind should return user id', function () {
const result = adapter.afterFind(authData);
expect(result).toEqual({ id: 'validUserId' });
});
});
describe('LinkedInAdapter E2E Test', function () {
beforeEach(async function () {
await reconfigureServer({
auth: {
linkedin: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
},
},
});
});
it('should log in user using LinkedIn adapter successfully (secure)', async function () {
mockFetch([
{
url: 'https://www.linkedin.com/oauth/v2/accessToken',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.linkedin.com/v2/me',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
}),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'https://example.com/callback' };
const user = await Parse.User.logInWith('linkedin', { authData });
expect(user.id).toBeDefined();
expect(global.fetch).toHaveBeenCalledWith(
'https://www.linkedin.com/oauth/v2/accessToken',
jasmine.any(Object)
);
expect(global.fetch).toHaveBeenCalledWith(
'https://api.linkedin.com/v2/me',
jasmine.any(Object)
);
});
it('should handle error when LinkedIn returns invalid user data', async function () {
mockFetch([
{
url: 'https://www.linkedin.com/oauth/v2/accessToken',
method: 'POST',
response: {
ok: true,
json: () =>
Promise.resolve({
access_token: 'mockAccessToken123',
}),
},
},
{
url: 'https://api.linkedin.com/v2/me',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'https://example.com/callback' };
await expectAsync(Parse.User.logInWith('linkedin', { authData })).toBeRejectedWithError(
'LinkedIn API request failed.'
);
expect(global.fetch).toHaveBeenCalledWith(
'https://www.linkedin.com/oauth/v2/accessToken',
jasmine.any(Object)
);
expect(global.fetch).toHaveBeenCalledWith(
'https://api.linkedin.com/v2/me',
jasmine.any(Object)
);
});
it('secure does not support insecure payload if not enabled', async function () {
mockFetch();
const authData = { id: 'mockUserId', access_token: 'mockAccessToken123' };
await expectAsync(Parse.User.logInWith('linkedin', { authData })).toBeRejectedWithError(
'LinkedIn code is required.'
);
expect(global.fetch).not.toHaveBeenCalled();
});
it('insecure mode supports insecure payload if enabled', async function () {
await reconfigureServer({
auth: {
linkedin: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: true,
},
},
});
mockFetch([
{
url: 'https://api.linkedin.com/v2/me',
method: 'GET',
response: {
ok: true,
json: () =>
Promise.resolve({
id: 'mockUserId',
}),
},
},
]);
const authData = { id: 'mockUserId', access_token: 'mockAccessToken123' };
const user = await Parse.User.logInWith('linkedin', { authData });
expect(user.id).toBeDefined();
expect(global.fetch).toHaveBeenCalledWith(
'https://api.linkedin.com/v2/me',
jasmine.any(Object)
);
});
});
});
+307
View File
@@ -0,0 +1,307 @@
const MicrosoftAdapter = require('../../../lib/Adapters/Auth/microsoft').default;
describe('MicrosoftAdapter', function () {
let adapter;
const validOptions = {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: false,
};
beforeEach(function () {
adapter = new MicrosoftAdapter.constructor();
});
describe('Test configuration errors', function () {
it('should throw error for missing options', function () {
const invalidOptions = [null, undefined, {}, { clientId: 'validClientId' }];
for (const options of invalidOptions) {
expect(() => {
adapter.validateOptions(options);
}).toThrow();
}
});
it('should validate options successfully with valid parameters', function () {
expect(() => {
adapter.validateOptions(validOptions);
}).not.toThrow();
expect(adapter.clientId).toBe(validOptions.clientId);
expect(adapter.clientSecret).toBe(validOptions.clientSecret);
expect(adapter.enableInsecureAuth).toBe(validOptions.enableInsecureAuth);
});
});
describe('Test getUserFromAccessToken', function () {
it('should fetch user successfully', async function () {
mockFetch([
{
url: 'https://graph.microsoft.com/v1.0/me',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ id: 'validUserId' }),
},
},
]);
const user = await adapter.getUserFromAccessToken('validToken');
expect(global.fetch).toHaveBeenCalledWith('https://graph.microsoft.com/v1.0/me', {
headers: {
Authorization: 'Bearer validToken',
},
method: 'GET',
});
expect(user).toEqual({ id: 'validUserId' });
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://graph.microsoft.com/v1.0/me',
method: 'GET',
response: { ok: false },
},
]);
await expectAsync(adapter.getUserFromAccessToken('invalidToken')).toBeRejectedWith(
new Error('Microsoft API request failed.')
);
});
});
describe('Test getAccessTokenFromCode', function () {
it('should fetch token successfully', async function () {
mockFetch([
{
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validToken' }),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com' };
const token = await adapter.getAccessTokenFromCode(authData);
expect(global.fetch).toHaveBeenCalledWith('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: jasmine.any(URLSearchParams),
});
expect(token).toEqual('validToken');
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
method: 'POST',
response: { ok: false },
},
]);
const authData = { code: 'invalidCode', redirect_uri: 'http://example.com' };
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWith(
new Error('Microsoft API request failed.')
);
});
});
describe('Test secure authentication flow', function () {
it('should exchange code for access token and fetch user data', async function () {
spyOn(adapter, 'getAccessTokenFromCode').and.returnValue(Promise.resolve('validToken'));
spyOn(adapter, 'getUserFromAccessToken').and.returnValue(Promise.resolve({ id: 'validUserId' }));
const authData = { code: 'validCode', redirect_uri: 'http://example.com' };
await adapter.beforeFind(authData);
expect(authData.access_token).toBe('validToken');
expect(authData.id).toBe('validUserId');
});
it('should throw error if user data cannot be fetched', async function () {
spyOn(adapter, 'getAccessTokenFromCode').and.returnValue(Promise.resolve('validToken'));
spyOn(adapter, 'getUserFromAccessToken').and.throwError('Microsoft API request failed.');
const authData = { code: 'validCode', redirect_uri: 'http://example.com' };
await expectAsync(adapter.beforeFind(authData)).toBeRejectedWith(
new Error('Microsoft API request failed.')
);
});
});
describe('Test insecure authentication flow', function () {
beforeEach(function () {
adapter.enableInsecureAuth = true;
});
it('should validate insecure auth and match user id', async function () {
spyOn(adapter, 'getUserFromAccessToken').and.returnValue(
Promise.resolve({ id: 'validUserId' })
);
const authData = { access_token: 'validToken', id: 'validUserId' };
await expectAsync(adapter.beforeFind(authData)).toBeResolved();
});
it('should throw error if insecure auth user id does not match', async function () {
spyOn(adapter, 'getUserFromAccessToken').and.returnValue(
Promise.resolve({ id: 'invalidUserId' })
);
const authData = { access_token: 'validToken', id: 'validUserId' };
await expectAsync(adapter.beforeFind(authData)).toBeRejectedWith(
new Error('Microsoft auth is invalid for this user.')
);
});
});
describe('MicrosoftAdapter E2E Tests', () => {
beforeEach(async () => {
// Simulate reconfiguring the server with Microsoft auth options
await reconfigureServer({
auth: {
microsoft: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: false,
},
},
});
});
it('should authenticate user successfully using MicrosoftAdapter', async () => {
mockFetch([
{
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validAccessToken' }),
},
},
{
url: 'https://graph.microsoft.com/v1.0/me',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ id: 'user123' }),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
const user = await Parse.User.logInWith('microsoft', { authData });
expect(user.id).toBeDefined();
});
it('should handle invalid code error gracefully', async () => {
mockFetch([
{
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
method: 'POST',
response: { ok: false, statusText: 'Invalid code' },
},
]);
const authData = { code: 'invalidCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(Parse.User.logInWith('microsoft', { authData })).toBeRejectedWithError(
'Microsoft API request failed.'
);
});
it('should handle error when fetching user data fails', async () => {
mockFetch([
{
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validAccessToken' }),
},
},
{
url: 'https://graph.microsoft.com/v1.0/me',
method: 'GET',
response: { ok: false, statusText: 'Unauthorized' },
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(Parse.User.logInWith('microsoft', { authData })).toBeRejectedWithError(
'Microsoft API request failed.'
);
});
it('should allow insecure auth when enabled', async () => {
mockFetch([
{
url: 'https://graph.microsoft.com/v1.0/me',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({
id: 'user123',
}),
},
},
])
await reconfigureServer({
auth: {
microsoft: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: true,
},
},
});
const authData = { access_token: 'validAccessToken', id: 'user123' };
const user = await Parse.User.logInWith('microsoft', { authData });
expect(user.id).toBeDefined();
});
it('should reject insecure auth when user id does not match', async () => {
mockFetch([
{
url: 'https://graph.microsoft.com/v1.0/me',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({
id: 'incorrectUser',
}),
},
},
])
await reconfigureServer({
auth: {
microsoft: {
clientId: 'validClientId',
clientSecret: 'validClientSecret',
enableInsecureAuth: true,
},
},
});
const authData = { access_token: 'validAccessToken', id: 'incorrectUserId' };
await expectAsync(Parse.User.logInWith('microsoft', { authData })).toBeRejectedWithError(
'Microsoft auth is invalid for this user.'
);
});
});
});
+448
View File
@@ -0,0 +1,448 @@
const OAuth2Adapter = require('../../../lib/Adapters/Auth/oauth2').default;
describe('OAuth2Adapter', () => {
let adapter;
const validOptions = {
tokenIntrospectionEndpointUrl: 'https://provider.com/introspect',
useridField: 'sub',
appidField: 'aud',
appIds: ['valid-app-id'],
authorizationHeader: 'Bearer validAuthToken',
};
beforeEach(() => {
adapter = new OAuth2Adapter.constructor();
adapter.validateOptions(validOptions);
});
describe('validateAppId', () => {
it('should validate app ID successfully', async () => {
const authData = { access_token: 'validAccessToken' };
const mockResponse = {
[validOptions.appidField]: 'valid-app-id',
};
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapter.validateAppId(validOptions.appIds, authData, validOptions)
).toBeResolved();
});
it('should throw an error if app ID is invalid', async () => {
const authData = { access_token: 'validAccessToken' };
const mockResponse = {
[validOptions.appidField]: 'invalid-app-id',
};
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapter.validateAppId(validOptions.appIds, authData, validOptions)
).toBeRejectedWithError('OAuth2: Invalid app ID.');
});
});
describe('validateAuthData', () => {
it('should validate auth data successfully', async () => {
const authData = { id: 'user-id', access_token: 'validAccessToken' };
const mockResponse = {
active: true,
[validOptions.useridField]: 'user-id',
};
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapter.validateAuthData(authData, null, validOptions)
).toBeResolvedTo({});
});
it('should throw an error if the token is inactive', async () => {
const authData = { id: 'user-id', access_token: 'validAccessToken' };
const mockResponse = { active: false };
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapter.validateAuthData(authData, null, validOptions)
).toBeRejectedWith(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'OAuth2 access token is invalid for this user.'));
});
it('should throw an error if user ID does not match', async () => {
const authData = { id: 'user-id', access_token: 'validAccessToken' };
const mockResponse = {
active: true,
[validOptions.useridField]: 'different-user-id',
};
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapter.validateAuthData(authData, null, validOptions)
).toBeRejectedWithError('OAuth2 access token is invalid for this user.');
});
it('should default useridField to sub and reject mismatched user ID', async () => {
const adapterNoUseridField = new OAuth2Adapter.constructor();
adapterNoUseridField.validateOptions({
tokenIntrospectionEndpointUrl: 'https://provider.example.com/introspect',
});
const authData = { id: 'victim-user-id', access_token: 'attackerToken' };
const mockResponse = {
active: true,
sub: 'attacker-user-id',
};
mockFetch([
{
url: 'https://provider.example.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapterNoUseridField.validateAuthData(authData, null, {})
).toBeRejectedWithError('OAuth2 access token is invalid for this user.');
});
it('should default useridField to sub and accept matching user ID', async () => {
const adapterNoUseridField = new OAuth2Adapter.constructor();
adapterNoUseridField.validateOptions({
tokenIntrospectionEndpointUrl: 'https://provider.example.com/introspect',
});
const authData = { id: 'user-id', access_token: 'validAccessToken' };
const mockResponse = {
active: true,
sub: 'user-id',
};
mockFetch([
{
url: 'https://provider.example.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
await expectAsync(
adapterNoUseridField.validateAuthData(authData, null, {})
).toBeResolvedTo({});
});
});
describe('requestTokenInfo', () => {
it('should fetch token info successfully', async () => {
const mockResponse = { active: true };
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
const result = await adapter.requestTokenInfo(
'validAccessToken',
validOptions
);
expect(result).toEqual(mockResponse);
});
it('should throw an error if the introspection endpoint URL is missing', async () => {
const options = { ...validOptions, tokenIntrospectionEndpointUrl: null };
expect(
() => adapter.validateOptions(options)
).toThrow(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'OAuth2 token introspection endpoint URL is missing.'));
});
it('should throw an error if the response is not ok', async () => {
mockFetch([
{
url: validOptions.tokenIntrospectionEndpointUrl,
method: 'POST',
response: {
ok: false,
statusText: 'Bad Request',
},
},
]);
await expectAsync(
adapter.requestTokenInfo('invalidAccessToken')
).toBeRejectedWithError('OAuth2 token introspection request failed.');
});
});
describe('OAuth2Adapter E2E Tests', () => {
beforeEach(async () => {
// Simulate reconfiguring the server with OAuth2 auth options
await reconfigureServer({
auth: {
mockOauth: {
tokenIntrospectionEndpointUrl: 'https://provider.com/introspect',
useridField: 'sub',
appidField: 'aud',
appIds: ['valid-app-id'],
authorizationHeader: 'Bearer validAuthToken',
oauth2: true
},
},
});
});
it('should validate and authenticate user successfully', async () => {
mockFetch([
{
url: 'https://provider.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({
active: true,
sub: 'user123',
aud: 'valid-app-id',
}),
},
},
]);
const authData = { access_token: 'validAccessToken', id: 'user123' };
const user = await Parse.User.logInWith('mockOauth', { authData });
expect(user.id).toBeDefined();
expect(user.get('authData').mockOauth.id).toEqual('user123');
});
it('should reject authentication for inactive token', async () => {
mockFetch([
{
url: 'https://provider.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ active: false, aud: ['valid-app-id'] }),
},
},
]);
const authData = { access_token: 'inactiveToken', id: 'user123' };
await expectAsync(Parse.User.logInWith('mockOauth', { authData })).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'OAuth2 access token is invalid for this user.')
);
});
it('should reject authentication for mismatched user ID', async () => {
mockFetch([
{
url: 'https://provider.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({
active: true,
sub: 'different-user',
aud: 'valid-app-id',
}),
},
},
]);
const authData = { access_token: 'validAccessToken', id: 'user123' };
await expectAsync(Parse.User.logInWith('mockOauth', { authData })).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'OAuth2 access token is invalid for this user.')
);
});
it('should reject authentication for invalid app ID', async () => {
mockFetch([
{
url: 'https://provider.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({
active: true,
sub: 'user123',
aud: 'invalid-app-id',
}),
},
},
]);
const authData = { access_token: 'validAccessToken', id: 'user123' };
await expectAsync(Parse.User.logInWith('mockOauth', { authData })).toBeRejectedWithError(
'OAuth2: Invalid app ID.'
);
});
it('should send the correct access token to the introspection endpoint during app ID validation', async () => {
const capturedTokens = [];
const originalFetch = global.fetch;
try {
global.fetch = async (url, options) => {
if (typeof url === 'string' && url === 'https://provider.com/introspect') {
const body = options?.body?.toString() || '';
const token = new URLSearchParams(body).get('token');
capturedTokens.push(token);
return {
ok: true,
json: () => Promise.resolve({
active: true,
sub: 'user123',
aud: 'valid-app-id',
}),
};
}
return originalFetch(url, options);
};
const authData = { access_token: 'myRealAccessToken', id: 'user123' };
const user = await Parse.User.logInWith('mockOauth', { authData });
expect(user.id).toBeDefined();
// With appidField configured, validateAppId and validateAuthData both call requestTokenInfo.
// Both should receive the actual access token, not 'undefined' from argument mismatch.
expect(capturedTokens.length).toBeGreaterThanOrEqual(2);
for (const token of capturedTokens) {
expect(token).toBe('myRealAccessToken');
}
} finally {
global.fetch = originalFetch;
}
});
it('should reject account takeover when useridField is omitted and attacker uses their own token with victim ID', async () => {
await reconfigureServer({
auth: {
mockOauth: {
tokenIntrospectionEndpointUrl: 'https://provider.example.com/introspect',
authorizationHeader: 'Bearer validAuthToken',
oauth2: true,
},
},
});
// Victim signs up with their own valid token
mockFetch([
{
url: 'https://provider.example.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({
active: true,
sub: 'victim-sub-id',
}),
},
},
]);
const victimAuthData = { access_token: 'victimToken', id: 'victim-sub-id' };
const victim = await Parse.User.logInWith('mockOauth', { authData: victimAuthData });
expect(victim.id).toBeDefined();
// Attacker tries to log in with their own valid token but claims victim's ID
mockFetch([
{
url: 'https://provider.example.com/introspect',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({
active: true,
sub: 'attacker-sub-id',
}),
},
},
]);
const attackerAuthData = { access_token: 'attackerToken', id: 'victim-sub-id' };
await expectAsync(Parse.User.logInWith('mockOauth', { authData: attackerAuthData })).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'OAuth2 access token is invalid for this user.')
);
});
it('should handle error when token introspection endpoint is missing', async () => {
await reconfigureServer({
auth: {
mockOauth: {
tokenIntrospectionEndpointUrl: null,
useridField: 'sub',
appidField: 'aud',
appIds: ['valid-app-id'],
authorizationHeader: 'Bearer validAuthToken',
oauth2: true
},
},
});
const authData = { access_token: 'validAccessToken', id: 'user123' };
await expectAsync(Parse.User.logInWith('mockOauth', { authData })).toBeRejectedWith(
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'OAuth2 token introspection endpoint URL is missing.')
);
});
});
});
+252
View File
@@ -0,0 +1,252 @@
const QqAdapter = require('../../../lib/Adapters/Auth/qq').default;
describe('QqAdapter', () => {
let adapter;
beforeEach(() => {
adapter = new QqAdapter.constructor();
});
describe('getUserFromAccessToken', () => {
it('should fetch user data successfully', async () => {
const mockResponse = `callback({"client_id":"validAppId","openid":"user123"})`;
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/me',
method: 'GET',
response: {
ok: true,
text: () => Promise.resolve(mockResponse),
},
},
]);
const result = await adapter.getUserFromAccessToken('validAccessToken');
expect(result).toEqual({ client_id: 'validAppId', openid: 'user123' });
});
it('should throw an error if the API request fails', async () => {
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/me',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
await expectAsync(
adapter.getUserFromAccessToken('invalidAccessToken')
).toBeRejectedWithError('qq API request failed.');
});
});
describe('getAccessTokenFromCode', () => {
it('should fetch access token successfully', async () => {
const mockResponse = `callback({"access_token":"validAccessToken","expires_in":3600,"refresh_token":"refreshToken"})`;
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/token',
method: 'GET',
response: {
ok: true,
text: () => Promise.resolve(mockResponse),
},
},
]);
const result = await adapter.getAccessTokenFromCode({
code: 'validCode',
redirect_uri: 'https://your-redirect-uri.com/callback',
});
expect(result).toBe('validAccessToken');
});
it('should throw an error if the API request fails', async () => {
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/token',
method: 'GET',
response: {
ok: false,
statusText: 'Bad Request',
},
},
]);
await expectAsync(
adapter.getAccessTokenFromCode({
code: 'invalidCode',
redirect_uri: 'https://your-redirect-uri.com/callback',
})
).toBeRejectedWithError('qq API request failed.');
});
});
describe('parseResponseData', () => {
it('should parse valid callback response data', () => {
const response = `callback({"key":"value"})`;
const result = adapter.parseResponseData(response);
expect(result).toEqual({ key: 'value' });
});
it('should throw an error if the response data is invalid', () => {
const response = 'invalid response';
expect(() => adapter.parseResponseData(response)).toThrowError(
'qq auth is invalid for this user.'
);
});
});
describe('QqAdapter E2E Test', () => {
beforeEach(async () => {
await reconfigureServer({
auth: {
qq: {
clientId: 'validAppId',
clientSecret: 'validAppSecret',
},
},
});
});
it('should log in user using Qq adapter successfully', async () => {
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/token',
method: 'GET',
response: {
ok: true,
text: () =>
Promise.resolve(
`callback({"access_token":"mockAccessToken","expires_in":3600})`
),
},
},
{
url: 'https://graph.qq.com/oauth2.0/me',
method: 'GET',
response: {
ok: true,
text: () =>
Promise.resolve(
`callback({"client_id":"validAppId","openid":"user123"})`
),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'https://your-redirect-uri.com/callback' };
const user = await Parse.User.logInWith('qq', { authData });
expect(user.id).toBeDefined();
});
it('should handle error when Qq returns invalid code', async () => {
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/token',
method: 'GET',
response: {
ok: false,
statusText: 'Invalid code',
},
},
]);
const authData = { code: 'invalidCode', redirect_uri: 'https://your-redirect-uri.com/callback' };
await expectAsync(Parse.User.logInWith('qq', { authData })).toBeRejectedWithError(
'qq API request failed.'
);
});
it('should handle error when Qq returns invalid user data', async () => {
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/token',
method: 'GET',
response: {
ok: true,
text: () =>
Promise.resolve(
`callback({"access_token":"mockAccessToken","expires_in":3600})`
),
},
},
{
url: 'https://graph.qq.com/oauth2.0/me',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'https://your-redirect-uri.com/callback' };
await expectAsync(Parse.User.logInWith('qq', { authData })).toBeRejectedWithError(
'qq API request failed.'
);
});
it('e2e secure does not support insecure payload', async () => {
mockFetch();
const authData = { id: 'mockUserId', access_token: 'mockAccessToken' };
await expectAsync(Parse.User.logInWith('qq', { authData })).toBeRejectedWithError(
'qq code is required.'
);
});
it('e2e insecure does support secure payload', async () => {
await reconfigureServer({
auth: {
qq: {
appId: 'validAppId',
appSecret: 'validAppSecret',
enableInsecureAuth: true,
},
},
});
mockFetch([
{
url: 'https://graph.qq.com/oauth2.0/token',
method: 'GET',
response: {
ok: true,
text: () =>
Promise.resolve(
`callback({"access_token":"mockAccessToken","expires_in":3600})`
),
},
},
{
url: 'https://graph.qq.com/oauth2.0/me',
method: 'GET',
response: {
ok: true,
text: () =>
Promise.resolve(
`callback({"client_id":"validAppId","openid":"user123"})`
),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'https://your-redirect-uri.com/callback' };
const user = await Parse.User.logInWith('qq', { authData });
expect(user.id).toBeDefined();
});
});
});
+113
View File
@@ -0,0 +1,113 @@
const SpotifyAdapter = require('../../../lib/Adapters/Auth/spotify').default;
describe('SpotifyAdapter', () => {
let adapter;
beforeEach(() => {
adapter = new SpotifyAdapter.constructor();
});
describe('getUserFromAccessToken', () => {
it('should fetch user data successfully', async () => {
const mockResponse = {
id: 'spotifyUser123',
};
mockFetch([
{
url: 'https://api.spotify.com/v1/me',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
const result = await adapter.getUserFromAccessToken('validAccessToken');
expect(result).toEqual({ id: 'spotifyUser123' });
});
it('should throw an error if the API request fails', async () => {
mockFetch([
{
url: 'https://api.spotify.com/v1/me',
method: 'GET',
response: {
ok: false,
statusText: 'Unauthorized',
},
},
]);
await expectAsync(adapter.getUserFromAccessToken('invalidAccessToken')).toBeRejectedWithError(
'Spotify API request failed.'
);
});
});
describe('getAccessTokenFromCode', () => {
it('should fetch access token successfully', async () => {
const mockResponse = {
access_token: 'validAccessToken',
expires_in: 3600,
refresh_token: 'refreshToken',
};
mockFetch([
{
url: 'https://accounts.spotify.com/api/token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve(mockResponse),
},
},
]);
const authData = {
code: 'validCode',
redirect_uri: 'https://your-redirect-uri.com/callback',
code_verifier: 'validCodeVerifier',
};
const result = await adapter.getAccessTokenFromCode(authData);
expect(result).toEqual(mockResponse);
});
it('should throw an error if authData is missing required fields', async () => {
const authData = {
redirect_uri: 'https://your-redirect-uri.com/callback',
};
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWithError(
'Spotify auth configuration authData.code and/or authData.redirect_uri and/or authData.code_verifier.'
);
});
it('should throw an error if the API request fails', async () => {
mockFetch([
{
url: 'https://accounts.spotify.com/api/token',
method: 'POST',
response: {
ok: false,
statusText: 'Bad Request',
},
},
]);
const authData = {
code: 'invalidCode',
redirect_uri: 'https://your-redirect-uri.com/callback',
code_verifier: 'invalidCodeVerifier',
};
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWithError(
'Spotify API request failed.'
);
});
});
});
+120
View File
@@ -0,0 +1,120 @@
const TwitterAuthAdapter = require('../../../lib/Adapters/Auth/twitter').default;
describe('TwitterAuthAdapter', function () {
let adapter;
const validOptions = {
consumer_key: 'validConsumerKey',
consumer_secret: 'validConsumerSecret',
};
beforeEach(function () {
adapter = new TwitterAuthAdapter.constructor();
});
describe('Test configuration errors', function () {
it('should throw an error when options are missing', function () {
expect(() => adapter.validateOptions()).toThrowError('Twitter auth options are required.');
});
it('should throw an error when consumer_key and consumer_secret are missing for secure auth', function () {
const options = { enableInsecureAuth: false };
expect(() => adapter.validateOptions(options)).toThrowError(
'Consumer key and secret are required for secure Twitter auth.'
);
});
it('should not throw an error when valid options are provided', function () {
expect(() => adapter.validateOptions(validOptions)).not.toThrow();
});
});
describe('Validate Insecure Auth', function () {
it('should throw an error if oauth_token or oauth_token_secret are missing', async function () {
const authData = { oauth_token: 'validToken' }; // Missing oauth_token_secret
await expectAsync(adapter.validateInsecureAuth(authData, validOptions)).toBeRejectedWithError(
'Twitter insecure auth requires oauth_token and oauth_token_secret.'
);
});
it('should validate insecure auth successfully when data matches', async function () {
spyOn(adapter, 'request').and.returnValue(
Promise.resolve({
json: () => Promise.resolve({ id: 'validUserId' }),
})
);
const authData = {
id: 'validUserId',
oauth_token: 'validToken',
oauth_token_secret: 'validSecret',
};
await expectAsync(adapter.validateInsecureAuth(authData, validOptions)).toBeResolved();
});
it('should throw an error when user ID does not match', async function () {
spyOn(adapter, 'request').and.returnValue(
Promise.resolve({
json: () => Promise.resolve({ id: 'invalidUserId' }),
})
);
const authData = {
id: 'validUserId',
oauth_token: 'validToken',
oauth_token_secret: 'validSecret',
};
await expectAsync(adapter.validateInsecureAuth(authData, validOptions)).toBeRejectedWithError(
'Twitter auth is invalid for this user.'
);
});
});
describe('End-to-End Tests', function () {
beforeEach(async function () {
await reconfigureServer({
auth: {
twitter: validOptions,
}
})
});
it('should authenticate user successfully using validateAuthData', async function () {
spyOn(adapter, 'exchangeAccessToken').and.returnValue(
Promise.resolve({ oauth_token: 'validToken', user_id: 'validUserId' })
);
const authData = {
oauth_token: 'validToken',
oauth_verifier: 'validVerifier',
};
await expectAsync(adapter.validateAuthData(authData, validOptions)).toBeResolved();
expect(authData.id).toBe('validUserId');
expect(authData.auth_token).toBe('validToken');
});
it('should handle multiple configurations and validate successfully', async function () {
const authData = {
consumer_key: 'validConsumerKey',
oauth_token: 'validToken',
oauth_token_secret: 'validSecret',
};
const optionsArray = [
{ consumer_key: 'invalidKey', consumer_secret: 'invalidSecret' },
validOptions,
];
const selectedOption = adapter.handleMultipleConfigurations(authData, optionsArray);
expect(selectedOption).toEqual(validOptions);
});
it('should throw an error when no matching configuration is found', function () {
const authData = { consumer_key: 'missingKey' };
const optionsArray = [validOptions];
expect(() => adapter.handleMultipleConfigurations(authData, optionsArray)).toThrowError(
'Twitter auth is invalid for this user.'
);
});
});
});
+236
View File
@@ -0,0 +1,236 @@
const WeChatAdapter = require('../../../lib/Adapters/Auth/wechat').default;
describe('WeChatAdapter', function () {
let adapter;
beforeEach(function () {
adapter = new WeChatAdapter.constructor();
});
describe('Test getUserFromAccessToken', function () {
it('should fetch user successfully', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/auth?access_token=validToken&openid=validOpenId',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ errcode: 0, id: 'validUserId' }),
},
},
]);
const user = await adapter.getUserFromAccessToken('validToken', { id: 'validOpenId' });
expect(global.fetch).toHaveBeenCalledWith(
'https://api.weixin.qq.com/sns/auth?access_token=validToken&openid=validOpenId',
jasmine.any(Object)
);
expect(user).toEqual({ errcode: 0, id: 'validUserId' });
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/auth?access_token=invalidToken&openid=undefined',
method: 'GET',
response: {
ok: false,
json: () => Promise.resolve({ errcode: 40013, errmsg: 'Invalid token' }),
},
},
]);
await expectAsync(adapter.getUserFromAccessToken('invalidToken', 'invalidOpenId')).toBeRejectedWith(
jasmine.objectContaining({ message: 'WeChat auth is invalid for this user.' })
);
});
});
describe('Test getAccessTokenFromCode', function () {
it('should fetch access token successfully', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=validAppId&secret=validAppSecret&code=validCode&grant_type=authorization_code',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validToken', errcode: 0 }),
},
},
]);
adapter.validateOptions({ clientId: 'validAppId', clientSecret: 'validAppSecret' });
const authData = { code: 'validCode' };
const token = await adapter.getAccessTokenFromCode(authData);
expect(global.fetch).toHaveBeenCalledWith(
'https://api.weixin.qq.com/sns/oauth2/access_token?appid=validAppId&secret=validAppSecret&code=validCode&grant_type=authorization_code',
jasmine.any(Object)
);
expect(token).toEqual('validToken');
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=validAppId&secret=validAppSecret&code=invalidCode&grant_type=authorization_code',
method: 'GET',
response: {
ok: false,
json: () => Promise.resolve({ errcode: 40029, errmsg: 'Invalid code' }),
},
},
]);
adapter.validateOptions({ clientId: 'validAppId', clientSecret: 'validAppSecret' });
const authData = { code: 'invalidCode' };
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWith(
jasmine.objectContaining({ message: 'WeChat auth is invalid for this user.' })
);
});
});
describe('WeChatAdapter E2E Tests', function () {
beforeEach(async () => {
await reconfigureServer({
auth: {
wechat: {
clientId: 'validAppId',
clientSecret: 'validAppSecret',
enableInsecureAuth: false,
},
},
});
});
it('should authenticate user successfully using WeChatAdapter', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=validAppId&secret=validAppSecret&code=validCode&grant_type=authorization_code',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validAccessToken', openid: 'user123', errcode: 0 }),
},
},
{
url: 'https://api.weixin.qq.com/sns/auth?access_token=validAccessToken&openid=user123',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ errcode: 0, id: 'user123' }),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
const user = await Parse.User.logInWith('wechat', { authData });
expect(user.id).toBeDefined();
});
it('should handle invalid code error gracefully', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=validAppId&secret=validAppSecret&code=invalidCode&grant_type=authorization_code',
method: 'GET',
response: {
ok: false,
json: () => Promise.resolve({ errcode: 40029, errmsg: 'Invalid code' }),
},
},
]);
const authData = { code: 'invalidCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(Parse.User.logInWith('wechat', { authData })).toBeRejectedWith(
jasmine.objectContaining({ message: 'WeChat auth is invalid for this user.' })
);
});
it('should handle error when fetching user data fails', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=validAppId&secret=validAppSecret&code=validCode&grant_type=authorization_code',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validAccessToken', openid: 'user123', errcode: 0 }),
},
},
{
url: 'https://api.weixin.qq.com/sns/auth?access_token=validAccessToken&openid=user123',
method: 'GET',
response: {
ok: false,
json: () => Promise.resolve({ errcode: 40013, errmsg: 'Invalid token' }),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(Parse.User.logInWith('wechat', { authData })).toBeRejectedWith(
jasmine.objectContaining({ message: 'WeChat auth is invalid for this user.' })
);
});
it('should allow insecure auth when enabled', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/auth?access_token=validAccessToken&openid=user123',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ errcode: 0, id: 'user123' }),
},
},
]);
await reconfigureServer({
auth: {
wechat: {
appId: 'validAppId',
appSecret: 'validAppSecret',
enableInsecureAuth: true,
},
},
});
const authData = { access_token: 'validAccessToken', id: 'user123' };
const user = await Parse.User.logInWith('wechat', { authData });
expect(user.id).toBeDefined();
});
it('should reject insecure auth when user id does not match', async function () {
mockFetch([
{
url: 'https://api.weixin.qq.com/sns/auth?access_token=validAccessToken&openid=incorrectUserId',
method: 'GET',
response: {
ok: true,
json: () => Promise.resolve({ errcode: 0, id: 'incorrectUser' }),
},
},
]);
await reconfigureServer({
auth: {
wechat: {
appId: 'validAppId',
appSecret: 'validAppSecret',
enableInsecureAuth: true,
},
},
});
const authData = { access_token: 'validAccessToken', id: 'incorrectUserId' };
await expectAsync(Parse.User.logInWith('wechat', { authData })).toBeRejectedWith(
jasmine.objectContaining({ message: 'WeChat auth is invalid for this user.' })
);
});
});
});
+204
View File
@@ -0,0 +1,204 @@
const WeiboAdapter = require('../../../lib/Adapters/Auth/weibo').default;
describe('WeiboAdapter', function () {
let adapter;
beforeEach(function () {
adapter = new WeiboAdapter.constructor();
});
describe('Test configuration errors', function () {
it('should throw error if code or redirect_uri is missing', async function () {
const invalidAuthData = [
{},
{ code: 'validCode' },
{ redirect_uri: 'http://example.com/callback' },
];
for (const authData of invalidAuthData) {
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWith(
jasmine.objectContaining({
message: 'Weibo auth requires code and redirect_uri to be sent.',
})
);
}
});
});
describe('Test getUserFromAccessToken', function () {
it('should fetch user successfully', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/get_token_info',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ uid: 'validUserId' }),
},
},
]);
const authData = { id: 'validUserId' };
const user = await adapter.getUserFromAccessToken('validToken', authData);
expect(global.fetch).toHaveBeenCalledWith(
'https://api.weibo.com/oauth2/get_token_info',
jasmine.objectContaining({
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
})
);
expect(user).toEqual({ id: 'validUserId' });
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/get_token_info',
method: 'POST',
response: {
ok: false,
json: () => Promise.resolve({}),
},
},
]);
const authData = { id: 'invalidUserId' };
await expectAsync(adapter.getUserFromAccessToken('invalidToken', authData)).toBeRejectedWith(
jasmine.objectContaining({
message: 'Weibo auth is invalid for this user.',
})
);
});
});
describe('Test getAccessTokenFromCode', function () {
it('should fetch access token successfully', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/access_token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validToken', uid: 'validUserId' }),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
const token = await adapter.getAccessTokenFromCode(authData);
expect(global.fetch).toHaveBeenCalledWith(
'https://api.weibo.com/oauth2/access_token',
jasmine.objectContaining({
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
})
);
expect(token).toEqual('validToken');
});
it('should throw error for invalid response', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/access_token',
method: 'POST',
response: {
ok: false,
json: () => Promise.resolve({ errcode: 40029 }),
},
},
]);
const authData = { code: 'invalidCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(adapter.getAccessTokenFromCode(authData)).toBeRejectedWith(
jasmine.objectContaining({
message: 'Weibo auth is invalid for this user.',
})
);
});
});
describe('WeiboAdapter E2E Tests', function () {
beforeEach(async () => {
await reconfigureServer({
auth: {
weibo: {
clientId: 'validAppId',
clientSecret: 'validAppSecret',
},
}
});
});
it('should authenticate user successfully using WeiboAdapter', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/access_token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validAccessToken', uid: 'user123' }),
},
},
{
url: 'https://api.weibo.com/oauth2/get_token_info',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ uid: 'user123' }),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
const user = await Parse.User.logInWith('weibo', { authData });
expect(user.id).toBeDefined();
});
it('should handle invalid code error gracefully', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/access_token',
method: 'POST',
response: {
ok: false,
json: () => Promise.resolve({ errcode: 40029 }),
},
},
]);
const authData = { code: 'invalidCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(Parse.User.logInWith('weibo', { authData })).toBeRejectedWith(
jasmine.objectContaining({ message: 'Weibo auth is invalid for this user.' })
);
});
it('should handle error when fetching user data fails', async function () {
mockFetch([
{
url: 'https://api.weibo.com/oauth2/access_token',
method: 'POST',
response: {
ok: true,
json: () => Promise.resolve({ access_token: 'validAccessToken', uid: 'user123' }),
},
},
{
url: 'https://api.weibo.com/oauth2/get_token_info',
method: 'POST',
response: {
ok: false,
json: () => Promise.resolve({}),
},
},
]);
const authData = { code: 'validCode', redirect_uri: 'http://example.com/callback' };
await expectAsync(Parse.User.logInWith('weibo', { authData })).toBeRejectedWith(
jasmine.objectContaining({ message: 'Weibo auth is invalid for this user.' })
);
});
});
});
+41 -19
View File
@@ -5,6 +5,13 @@ const request = require('../lib/request');
const AudiencesRouter = require('../lib/Routers/AudiencesRouter').AudiencesRouter;
describe('AudiencesRouter', () => {
let loggerErrorSpy;
beforeEach(() => {
const logger = require('../lib/logger').default;
loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
});
it('uses find condition from request.body', done => {
const config = Config.get('test');
const androidAudienceRequest = {
@@ -29,9 +36,9 @@ describe('AudiencesRouter', () => {
const router = new AudiencesRouter();
rest
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
.create(config, auth.master(config), '_Audience', androidAudienceRequest)
.then(() => {
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
return rest.create(config, auth.master(config), '_Audience', iosAudienceRequest);
})
.then(() => {
return router.handleFind(request);
@@ -71,9 +78,9 @@ describe('AudiencesRouter', () => {
const router = new AudiencesRouter();
rest
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
.create(config, auth.master(config), '_Audience', androidAudienceRequest)
.then(() => {
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
return rest.create(config, auth.master(config), '_Audience', iosAudienceRequest);
})
.then(() => {
return router.handleFind(request);
@@ -112,9 +119,9 @@ describe('AudiencesRouter', () => {
Config.get('test');
const router = new AudiencesRouter();
rest
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
.create(config, auth.master(config), '_Audience', androidAudienceRequest)
.then(() => {
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
return rest.create(config, auth.master(config), '_Audience', iosAudienceRequest);
})
.then(() => {
return router.handleFind(request);
@@ -152,8 +159,8 @@ describe('AudiencesRouter', () => {
const router = new AudiencesRouter();
rest
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
.then(() => rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest))
.create(config, auth.master(config), '_Audience', androidAudienceRequest)
.then(() => rest.create(config, auth.master(config), '_Audience', iosAudienceRequest))
.then(() => router.handleFind(request))
.then(res => {
const response = res.response;
@@ -190,9 +197,9 @@ describe('AudiencesRouter', () => {
const router = new AudiencesRouter();
rest
.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
.create(config, auth.master(config), '_Audience', androidAudienceRequest)
.then(() => {
return rest.create(config, auth.nobody(config), '_Audience', iosAudienceRequest);
return rest.create(config, auth.master(config), '_Audience', iosAudienceRequest);
})
.then(() => {
return router.handleFind(request);
@@ -263,61 +270,71 @@ describe('AudiencesRouter', () => {
});
it('should only create with master key', done => {
loggerErrorSpy.calls.reset();
Parse._request('POST', 'push_audiences', {
name: 'My Audience',
query: JSON.stringify({ deviceType: 'ios' }),
}).then(
() => {},
error => {
expect(error.message).toEqual('unauthorized: master key is required');
expect(error.message).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
}
);
});
it('should only find with master key', done => {
loggerErrorSpy.calls.reset();
Parse._request('GET', 'push_audiences', {}).then(
() => {},
error => {
expect(error.message).toEqual('unauthorized: master key is required');
expect(error.message).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
}
);
});
it('should only get with master key', done => {
loggerErrorSpy.calls.reset();
Parse._request('GET', `push_audiences/someId`, {}).then(
() => {},
error => {
expect(error.message).toEqual('unauthorized: master key is required');
expect(error.message).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
}
);
});
it('should only update with master key', done => {
loggerErrorSpy.calls.reset();
Parse._request('PUT', `push_audiences/someId`, {
name: 'My Audience 2',
}).then(
() => {},
error => {
expect(error.message).toEqual('unauthorized: master key is required');
expect(error.message).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
}
);
});
it('should only delete with master key', done => {
loggerErrorSpy.calls.reset();
Parse._request('DELETE', `push_audiences/someId`, {}).then(
() => {},
error => {
expect(error.message).toEqual('unauthorized: master key is required');
expect(error.message).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
}
);
});
it_exclude_dbs(['postgres'])('should support legacy parse.com audience fields', done => {
it_id('af1111b5-3251-4b40-8f06-fb0fc624fa91')(it_exclude_dbs(['postgres']))('should support legacy parse.com audience fields', done => {
const database = Config.get(Parse.applicationId).database.adapter.database;
const now = new Date();
Parse._request(
@@ -339,11 +356,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 +380,9 @@ describe('AudiencesRouter', () => {
.catch(error => {
done.fail(error);
});
})
.catch(error => {
done.fail(error);
});
});
});
@@ -400,6 +421,7 @@ describe('AudiencesRouter', () => {
await reconfigureServer({
appId: 'test',
restAPIKey: 'test',
masterKey: 'test',
publicServerURL: 'http://localhost:8378/1',
});
try {
@@ -409,7 +431,7 @@ describe('AudiencesRouter', () => {
body: { lorem: 'ipsum', _method: 'POST' },
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'test',
'X-Parse-Master-Key': 'test',
'Content-Type': 'application/json',
},
});
+23 -40
View File
@@ -81,17 +81,6 @@ 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 () => {
@@ -117,6 +106,8 @@ describe('Auth', () => {
updatedAt: updatedAt.toISOString(),
}
);
Parse.Server.cacheController.clear();
await new Promise(resolve => setTimeout(resolve, 1000));
await session.fetch();
await new Promise(resolve => setTimeout(resolve, 1000));
await session.fetch();
@@ -152,35 +143,6 @@ describe('Auth', () => {
expect(userAuth.user.id).toBe(user.id);
});
it('should load auth without a config', async () => {
const user = new Parse.User();
await user.signUp({
username: 'hello',
password: 'password',
});
expect(user.getSessionToken()).not.toBeUndefined();
const userAuth = await getAuthForSessionToken({
sessionToken: user.getSessionToken(),
});
expect(userAuth.user instanceof Parse.User).toBe(true);
expect(userAuth.user.id).toBe(user.id);
});
it('should load auth with a config', async () => {
const user = new Parse.User();
await user.signUp({
username: 'hello',
password: 'password',
});
expect(user.getSessionToken()).not.toBeUndefined();
const userAuth = await getAuthForSessionToken({
sessionToken: user.getSessionToken(),
config: Config.get('test'),
});
expect(userAuth.user instanceof Parse.User).toBe(true);
expect(userAuth.user.id).toBe(user.id);
});
describe('getRolesForUser', () => {
const rolesNumber = 100;
@@ -271,3 +233,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);
});
});
+210
View File
@@ -0,0 +1,210 @@
'use strict';
const request = require('../lib/request');
const Config = require('../lib/Config');
describe('AuthData Unique Index', () => {
const fakeAuthProvider = {
validateAppId: () => Promise.resolve(),
validateAuthData: () => Promise.resolve(),
};
beforeEach(async () => {
await reconfigureServer({ auth: { fakeAuthProvider } });
});
it('should prevent concurrent signups with the same authData from creating duplicate users', async () => {
const authData = { fakeAuthProvider: { id: 'duplicate-test-id', token: 'token1' } };
// Fire multiple concurrent signup requests with the same authData
const concurrentRequests = Array.from({ length: 5 }, () =>
request({
method: 'POST',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'Content-Type': 'application/json',
},
url: 'http://localhost:8378/1/users',
body: { authData },
}).then(
response => ({ success: true, data: response.data }),
error => ({ success: false, error: error.data || error.message })
)
);
const results = await Promise.all(concurrentRequests);
const successes = results.filter(r => r.success);
const failures = results.filter(r => !r.success);
// All should either succeed (returning the same user) or fail with "this auth is already used"
// The key invariant: only ONE unique objectId should exist
const uniqueObjectIds = new Set(successes.map(r => r.data.objectId));
expect(uniqueObjectIds.size).toBe(1);
// Failures should be "this auth is already used" errors
for (const failure of failures) {
expect(failure.error.code).toBe(208);
expect(failure.error.error).toBe('this auth is already used');
}
// Verify only one user exists in the database with this authData
const query = new Parse.Query('_User');
query.equalTo('authData.fakeAuthProvider.id', 'duplicate-test-id');
const users = await query.find({ useMasterKey: true });
expect(users.length).toBe(1);
});
it('should prevent concurrent signups via batch endpoint with same authData', async () => {
const authData = { fakeAuthProvider: { id: 'batch-race-test-id', token: 'token1' } };
const response = await request({
method: 'POST',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'Content-Type': 'application/json',
},
url: 'http://localhost:8378/1/batch',
body: {
requests: Array.from({ length: 3 }, () => ({
method: 'POST',
path: '/1/users',
body: { authData },
})),
},
});
const results = response.data;
const successes = results.filter(r => r.success);
const failures = results.filter(r => r.error);
// All successes should reference the same user
const uniqueObjectIds = new Set(successes.map(r => r.success.objectId));
expect(uniqueObjectIds.size).toBe(1);
// Failures should be "this auth is already used" errors
for (const failure of failures) {
expect(failure.error.code).toBe(208);
expect(failure.error.error).toBe('this auth is already used');
}
// Verify only one user exists in the database with this authData
const query = new Parse.Query('_User');
query.equalTo('authData.fakeAuthProvider.id', 'batch-race-test-id');
const users = await query.find({ useMasterKey: true });
expect(users.length).toBe(1);
});
it('should allow sequential signups with different authData IDs', async () => {
const user1 = await Parse.User.logInWith('fakeAuthProvider', {
authData: { id: 'user-id-1', token: 'token1' },
});
const user2 = await Parse.User.logInWith('fakeAuthProvider', {
authData: { id: 'user-id-2', token: 'token2' },
});
expect(user1.id).toBeDefined();
expect(user2.id).toBeDefined();
expect(user1.id).not.toBe(user2.id);
});
it('should still allow login with authData after successful signup', async () => {
const authPayload = { authData: { id: 'login-test-id', token: 'token1' } };
// Signup
const user1 = await Parse.User.logInWith('fakeAuthProvider', authPayload);
expect(user1.id).toBeDefined();
// Login again with same authData — should return same user
const user2 = await Parse.User.logInWith('fakeAuthProvider', authPayload);
expect(user2.id).toBe(user1.id);
});
it('should skip startup index creation when createIndexAuthDataUniqueness is false', async () => {
const config = Config.get('test');
const adapter = config.database.adapter;
const spy = spyOn(adapter, 'ensureAuthDataUniqueness').and.callThrough();
// Temporarily set the option to false
const originalOptions = config.database.options.databaseOptions;
config.database.options.databaseOptions = { createIndexAuthDataUniqueness: false };
await config.database.performInitialization();
expect(spy).not.toHaveBeenCalled();
// Restore original options
config.database.options.databaseOptions = originalOptions;
});
it('should handle calling ensureAuthDataUniqueness multiple times (idempotent)', async () => {
const config = Config.get('test');
const adapter = config.database.adapter;
// Both calls should succeed (index creation is idempotent)
await adapter.ensureAuthDataUniqueness('fakeAuthProvider');
await adapter.ensureAuthDataUniqueness('fakeAuthProvider');
});
it('should log warning when index creation fails due to existing duplicates', async () => {
const config = Config.get('test');
const adapter = config.database.adapter;
// Spy on the adapter to simulate a duplicate value error
spyOn(adapter, 'ensureAuthDataUniqueness').and.callFake(() => {
return Promise.reject(
new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'duplicates exist')
);
});
const logSpy = spyOn(require('../lib/logger').logger, 'warn');
// Re-run performInitialization — should warn but not throw
await config.database.performInitialization();
expect(logSpy).toHaveBeenCalledWith(
jasmine.stringContaining('Unable to ensure uniqueness for auth data provider'),
jasmine.anything()
);
});
it('should prevent concurrent signups with same anonymous authData', async () => {
const anonymousId = 'anon-race-test-id';
const authData = { anonymous: { id: anonymousId } };
const concurrentRequests = Array.from({ length: 5 }, () =>
request({
method: 'POST',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
'Content-Type': 'application/json',
},
url: 'http://localhost:8378/1/users',
body: { authData },
}).then(
response => ({ success: true, data: response.data }),
error => ({ success: false, error: error.data || error.message })
)
);
const results = await Promise.all(concurrentRequests);
const successes = results.filter(r => r.success);
const failures = results.filter(r => !r.success);
// All successes should reference the same user
const uniqueObjectIds = new Set(successes.map(r => r.data.objectId));
expect(uniqueObjectIds.size).toBe(1);
// Failures should be "this auth is already used" errors
for (const failure of failures) {
expect(failure.error.code).toBe(208);
expect(failure.error.error).toBe('this auth is already used');
}
// Verify only one user exists in the database with this authData
const query = new Parse.Query('_User');
query.equalTo('authData.anonymous.id', anonymousId);
const users = await query.find({ useMasterKey: true });
expect(users.length).toBe(1);
});
});
File diff suppressed because it is too large Load Diff
+30 -13
View File
@@ -355,30 +355,20 @@ describe('Auth Adapter features', () => {
const authData = user.get('authData').modernAdapter3;
expect(authData).toEqual({ foo: 'bar' });
for (const call of afterSpy.calls.all()) {
const args = call.args[0];
const args = call.args[2];
if (args.user) {
user._objCount = args.user._objCount;
break;
}
}
expect(afterSpy).toHaveBeenCalledWith(
{ ip: '127.0.0.1', user, master: false },
{ id: 'modernAdapter3Data' },
undefined
undefined,
{ ip: '127.0.0.1', user, master: false },
);
expect(spy).toHaveBeenCalled();
});
it('should throw if no triggers found', async () => {
await reconfigureServer({ auth: { wrongAdapter } });
const user = new Parse.User();
await expectAsync(
user.save({ authData: { wrongAdapter: { id: 'wrongAdapter' } } })
).toBeRejectedWithError(
'Adapter is not configured. Implement either validateAuthData or all of the following: validateSetUp, validateLogin and validateUpdate'
);
});
it('should throw if policy does not match one of default/solo/additional', async () => {
const adapterWithBadPolicy = {
validateAppId: () => Promise.resolve(),
@@ -487,6 +477,33 @@ describe('Auth Adapter features', () => {
expect(baseAdapter2.validateAuthData).toHaveBeenCalledTimes(2);
});
it('should not perform authData validation twice when data mutated', async () => {
spyOn(baseAdapter, 'validateAuthData').and.resolveTo({});
await reconfigureServer({
auth: { baseAdapter },
allowExpiredAuthDataToken: false,
});
const user = new Parse.User();
await user.save({
authData: {
baseAdapter: { id: 'baseAdapter', token: "sometoken1" },
},
});
expect(baseAdapter.validateAuthData).toHaveBeenCalledTimes(1);
const user2 = new Parse.User();
await user2.save({
authData: {
baseAdapter: { id: 'baseAdapter', token: "sometoken2" },
},
});
expect(baseAdapter.validateAuthData).toHaveBeenCalledTimes(2);
});
it('should require additional provider if configured', async () => {
await reconfigureServer({
auth: { baseAdapter, additionalAdapter },
+64 -54
View File
@@ -1,5 +1,5 @@
'use strict';
const commander = require('../lib/cli/utils/commander').default;
let commander;
const definitions = require('../lib/cli/definitions/parse-server').default;
const liveQueryDefinitions = require('../lib/cli/definitions/parse-live-query-server').default;
const path = require('path');
@@ -28,6 +28,12 @@ const testDefinitions = {
};
describe('commander additions', () => {
beforeEach(() => {
const command = require('../lib/cli/utils/commander').default;
commander = new command.constructor();
commander.storeOptionsAsProperties();
commander.allowExcessArguments();
});
afterEach(done => {
commander.options = [];
delete commander.arg0;
@@ -207,6 +213,36 @@ describe('LiveQuery definitions', () => {
describe('execution', () => {
const binPath = path.resolve(__dirname, '../bin/parse-server');
let childProcess;
let aggregatedData;
function handleStdout(childProcess, done, aggregatedData, requiredData) {
childProcess.stdout.on('data', data => {
data = data.toString();
aggregatedData.push(data);
if (requiredData.every(required => aggregatedData.some(aggregated => aggregated.includes(required)))) {
done();
}
});
}
function handleStderr(childProcess, done) {
childProcess.stderr.on('data', data => {
data = data.toString();
if (!data.includes('[DEP0040] DeprecationWarning')) {
done.fail(data);
}
});
}
function handleError(childProcess, done) {
childProcess.on('error', err => {
done.fail(err);
});
}
beforeEach(() => {
aggregatedData = [];
});
afterEach(done => {
if (childProcess) {
@@ -218,28 +254,22 @@ describe('execution', () => {
}
});
it('should start Parse Server', done => {
it_id('a0ab74b4-f805-4e03-b31d-b5cd59e64495')(it)('should start Parse Server', done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
env.NODE_OPTIONS = '--dns-result-order=ipv4first --trace-deprecation';
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')) {
done();
}
});
childProcess.stderr.on('data', data => {
done.fail(data.toString());
});
handleStdout(childProcess, done, aggregatedData, ['parse-server running on']);
handleStderr(childProcess, done);
handleError(childProcess, done);
});
it('should start Parse Server with GraphQL', async done => {
it_id('d7165081-b133-4cba-901b-19128ce41301')(it)('should start Parse Server with GraphQL', async done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
env.NODE_OPTIONS = '--dns-result-order=ipv4first --trace-deprecation';
childProcess = spawn(
binPath,
[
@@ -255,23 +285,17 @@ describe('execution', () => {
],
{ env }
);
let output = '';
childProcess.stdout.on('data', data => {
data = data.toString();
output += data;
if (data.includes('GraphQL running on')) {
expect(output).toMatch('parse-server running on');
done();
}
});
childProcess.stderr.on('data', data => {
done.fail(data.toString());
});
handleStdout(childProcess, done, aggregatedData, [
'parse-server running on',
'GraphQL running on',
]);
handleStderr(childProcess, done);
handleError(childProcess, done);
});
it('should start Parse Server with GraphQL and Playground', async done => {
it_id('2769cdb4-ce8a-484d-8a91-635b5894ba7e')(it)('should start Parse Server with GraphQL and Playground', async done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
env.NODE_OPTIONS = '--dns-result-order=ipv4first --trace-deprecation';
childProcess = spawn(
binPath,
[
@@ -288,39 +312,25 @@ describe('execution', () => {
],
{ env }
);
let output = '';
childProcess.stdout.on('data', data => {
data = data.toString();
output += data;
if (data.includes('Playground running on')) {
expect(output).toMatch('GraphQL running on');
expect(output).toMatch('parse-server running on');
done();
}
});
childProcess.stderr.on('data', data => {
done.fail(data.toString());
});
handleStdout(childProcess, done, aggregatedData, [
'parse-server running on',
'Playground running on',
'GraphQL running on',
]);
handleStderr(childProcess, done);
handleError(childProcess, done);
});
it('can start Parse Server with auth via CLI', done => {
it_id('23caddd7-bfea-4869-8bd4-0f2cd283c8bd')(it)('can start Parse Server with auth via CLI', done => {
const env = { ...process.env };
env.NODE_OPTIONS = '--dns-result-order=ipv4first';
env.NODE_OPTIONS = '--dns-result-order=ipv4first --trace-deprecation';
childProcess = spawn(
binPath,
['--databaseURI', databaseURI, './spec/configs/CLIConfigAuth.json'],
{ env }
);
childProcess.stdout.on('data', data => {
data = data.toString();
console.log(data);
if (data.includes('parse-server running on')) {
done();
}
});
childProcess.stderr.on('data', data => {
data = data.toString();
done.fail(data.toString());
});
handleStdout(childProcess, done, aggregatedData, ['parse-server running on']);
handleStderr(childProcess, done);
handleError(childProcess, done);
});
});
+73 -23
View File
@@ -6,6 +6,9 @@ const validatorFail = () => {
const validatorSuccess = () => {
return true;
};
function testConfig() {
return Parse.Config.save({ internal: 'i', string: 's', number: 12 }, { internal: true });
}
describe('cloud validator', () => {
it('complete validator', async done => {
@@ -194,27 +197,6 @@ describe('cloud validator', () => {
});
});
it('set params on cloud functions', done => {
Parse.Cloud.define(
'hello',
() => {
return 'Hello world!';
},
{
fields: ['a'],
}
);
Parse.Cloud.run('hello', {})
.then(() => {
fail('function should have failed.');
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.VALIDATION_ERROR);
expect(error.message).toEqual('Validation failed. Please specify data for a.');
done();
});
});
it('allow params on cloud functions', done => {
Parse.Cloud.define(
'hello',
@@ -752,6 +734,38 @@ describe('cloud validator', () => {
done();
});
it_id('893eec0c-41bd-4adf-8f0a-306087ad8d61')(it)('basic beforeSave Parse.Config skipWithMasterKey', async () => {
Parse.Cloud.beforeSave(
Parse.Config,
() => {
throw 'beforeSaveFile should have resolved using master key.';
},
{
skipWithMasterKey: true,
}
);
const config = await testConfig();
expect(config.get('internal')).toBe('i');
expect(config.get('string')).toBe('s');
expect(config.get('number')).toBe(12);
});
it_id('91e739a4-6a38-405c-8f83-f36d48220734')(it)('basic afterSave Parse.Config skipWithMasterKey', async () => {
Parse.Cloud.afterSave(
Parse.Config,
() => {
throw 'beforeSaveFile should have resolved using master key.';
},
{
skipWithMasterKey: true,
}
);
const config = await testConfig();
expect(config.get('internal')).toBe('i');
expect(config.get('string')).toBe('s');
expect(config.get('number')).toBe(12);
});
it('beforeSave validateMasterKey and skipWithMasterKey fail', async function (done) {
Parse.Cloud.beforeSave(
'BeforeSave',
@@ -1462,7 +1476,7 @@ describe('cloud validator', () => {
});
it('validate afterSaveFile fail', async done => {
Parse.Cloud.beforeSave(Parse.File, () => {}, validatorFail);
Parse.Cloud.afterSave(Parse.File, () => {}, validatorFail);
try {
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save({ useMasterKey: true });
@@ -1517,6 +1531,42 @@ describe('cloud validator', () => {
}
});
it_id('32ca1a99-7f2b-429d-a7cf-62b6661d0af6')(it)('validate beforeSave Parse.Config', async () => {
Parse.Cloud.beforeSave(Parse.Config, () => {}, validatorSuccess);
const config = await testConfig();
expect(config.get('internal')).toBe('i');
expect(config.get('string')).toBe('s');
expect(config.get('number')).toBe(12);
});
it_id('c84d11e7-d09c-4843-ad98-f671511bf612')(it)('validate beforeSave Parse.Config fail', async () => {
Parse.Cloud.beforeSave(Parse.Config, () => {}, validatorFail);
try {
await testConfig();
fail('cloud function should have failed.');
} catch (e) {
expect(e.code).toBe(Parse.Error.VALIDATION_ERROR);
}
});
it_id('b18b9a6a-0e35-4b60-9771-30f53501df3c')(it)('validate afterSave Parse.Config', async () => {
Parse.Cloud.afterSave(Parse.Config, () => {}, validatorSuccess);
const config = await testConfig();
expect(config.get('internal')).toBe('i');
expect(config.get('string')).toBe('s');
expect(config.get('number')).toBe(12);
});
it_id('ef761222-1758-4614-b984-da84d73fc10c')(it)('validate afterSave Parse.Config fail', async () => {
Parse.Cloud.afterSave(Parse.Config, () => {}, validatorFail);
try {
await testConfig();
fail('cloud function should have failed.');
} catch (e) {
expect(e.code).toBe(Parse.Error.VALIDATION_ERROR);
}
});
it('Should have validator', async done => {
Parse.Cloud.define(
'myFunction',
@@ -1629,7 +1679,7 @@ describe('cloud validator', () => {
}
});
it('Logs on invalid config', () => {
it('Logs on multiple invalid configs', () => {
const fields = [
{
field: 'otherKey',
+931 -99
View File
File diff suppressed because it is too large Load Diff
+82 -18
View File
@@ -15,10 +15,17 @@ 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')
.catch(() => {})
.catch(() => { })
.then(loggedInUser => (user = loggedInUser))
.then(() => Parse.User.logIn(user.get('username'), 'abc'));
})
@@ -30,7 +37,7 @@ describe('Cloud Code Logger', () => {
// Note that helpers takes care of logout.
// see helpers.js:afterEach
it('should expose log to functions', () => {
it_id('02d53b97-3ec7-46fb-abb6-176fd6e85590')(it)('should expose log to functions', () => {
const spy = spyOn(Config.get('test').loggerController, 'log').and.callThrough();
Parse.Cloud.define('loggerTest', req => {
req.log.info('logTest', 'info log', { info: 'some log' });
@@ -60,7 +67,7 @@ describe('Cloud Code Logger', () => {
});
});
it('trigger should obfuscate password', done => {
it_id('768412f5-d32f-4134-89a6-08949781a6c0')(it)('trigger should obfuscate password', done => {
Parse.Cloud.beforeSave(Parse.User, req => {
return req.object;
});
@@ -75,7 +82,7 @@ describe('Cloud Code Logger', () => {
.then(null, e => done.fail(e));
});
it('should expose log to trigger', done => {
it_id('3c394047-272e-4728-9d02-9eaa660d2ed2')(it)('should expose log to trigger', done => {
Parse.Cloud.beforeSave('MyObject', req => {
req.log.info('beforeSave MyObject', 'info log', { info: 'some log' });
req.log.error('beforeSave MyObject', 'error log', {
@@ -113,7 +120,7 @@ describe('Cloud Code Logger', () => {
expect(truncatedString.length).toBe(1015); // truncate length + the string '... (truncated)'
});
it('should truncate input and result of long lines', done => {
it_id('4a009b1f-9203-49ca-8d48-5b45f4eedbdf')(it)('should truncate input and result of long lines', done => {
const longString = fs.readFileSync(loremFile, 'utf8');
Parse.Cloud.define('aFunction', req => {
return req.params;
@@ -131,8 +138,8 @@ describe('Cloud Code Logger', () => {
.then(null, e => done.fail(e));
});
it('should log an afterSave', done => {
Parse.Cloud.afterSave('MyObject', () => {});
it_id('9857e15d-bb18-478d-8a67-fdaad3e89565')(it)('should log an afterSave', done => {
Parse.Cloud.afterSave('MyObject', () => { });
new Parse.Object('MyObject')
.save()
.then(() => {
@@ -144,7 +151,7 @@ describe('Cloud Code Logger', () => {
.then(null, e => done.fail(e));
});
it('should log a denied beforeSave', done => {
it_id('ec13a296-f8b1-4fc6-985a-3593462edd9c')(it)('should log a denied beforeSave', done => {
Parse.Cloud.beforeSave('MyObject', () => {
throw 'uh oh!';
});
@@ -167,7 +174,7 @@ describe('Cloud Code Logger', () => {
});
});
it('should log cloud function success', done => {
it_id('3e0caa45-60d6-41af-829a-fd389710c132')(it)('should log cloud function success', done => {
Parse.Cloud.define('aFunction', () => {
return 'it worked!';
});
@@ -182,7 +189,7 @@ describe('Cloud Code Logger', () => {
});
});
it('should log cloud function execution using the custom log level', async done => {
it_id('8088de8a-7cba-4035-8b05-4a903307e674')(it)('should log cloud function execution using the custom log level', async () => {
Parse.Cloud.define('aFunction', () => {
return 'it worked!';
});
@@ -196,6 +203,7 @@ describe('Cloud Code Logger', () => {
expect(log).toEqual('info');
});
Parse.Cloud._removeAllHooks();
await reconfigureServer({
silent: true,
logLevels: {
@@ -204,6 +212,10 @@ describe('Cloud Code Logger', () => {
},
});
Parse.Cloud.define('bFunction', () => {
throw new Error('Failed');
});
spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough();
try {
@@ -214,15 +226,12 @@ describe('Cloud Code Logger', () => {
.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) => {
Parse.Cloud._removeAllHooks();
await reconfigureServer({
silent: true,
logLevel,
@@ -232,6 +241,9 @@ describe('Cloud Code Logger', () => {
},
});
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();
@@ -253,13 +265,13 @@ describe('Cloud Code Logger', () => {
expect(calls).toEqual({ beforeSave: 'warn', afterSave: undefined });
});
it('should log cloud function failure', done => {
it_id('97e0eafa-cde6-4a9a-9e53-7db98bacbc62')(it)('should log cloud function failure', done => {
Parse.Cloud.define('aFunction', () => {
throw 'it failed!';
});
Parse.Cloud.run('aFunction', { foo: 'bar' })
.catch(() => {})
.catch(() => { })
.then(() => {
const logs = spy.calls.all().reverse();
expect(logs[0].args[1]).toBe('Parse error: ');
@@ -280,6 +292,7 @@ describe('Cloud Code Logger', () => {
});
xit('should log a changed beforeSave indicating a change', done => {
pending('needs more work.....');
const logController = new LoggerController(new WinstonLoggerAdapter());
Parse.Cloud.beforeSave('MyObject', req => {
@@ -302,9 +315,9 @@ describe('Cloud Code Logger', () => {
done();
})
.then(null, e => done.fail(JSON.stringify(e)));
}).pend('needs more work.....');
});
it('cloud function should obfuscate password', done => {
it_id('b86e8168-8370-4730-a4ba-24ca3016ad66')(it)('cloud function should obfuscate password', done => {
Parse.Cloud.define('testFunction', () => {
return 'verify code success';
});
@@ -334,4 +347,55 @@ 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 () => {
Parse.Cloud._removeAllHooks();
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 () => {
Parse.Cloud._removeAllHooks();
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);
});
});
+226
View File
@@ -413,6 +413,13 @@ describe('DatabaseController', function () {
case_insensitive_username: { username: 1 },
case_insensitive_email: { email: 1 },
email_1: { email: 1 },
_email_verify_token: { _email_verify_token: 1 },
_perishable_token: { _perishable_token: 1 },
_auth_data_custom_id: { '_auth_data_custom.id': 1 },
_auth_data_facebook_id: { '_auth_data_facebook.id': 1 },
_auth_data_myoauth_id: { '_auth_data_myoauth.id': 1 },
_auth_data_shortLivedAuth_id: { '_auth_data_shortLivedAuth.id': 1 },
_auth_data_anonymous_id: { '_auth_data_anonymous.id': 1 },
});
}
);
@@ -437,9 +444,158 @@ describe('DatabaseController', function () {
_id_: { _id: 1 },
username_1: { username: 1 },
email_1: { email: 1 },
_email_verify_token: { _email_verify_token: 1 },
_perishable_token: { _perishable_token: 1 },
_auth_data_custom_id: { '_auth_data_custom.id': 1 },
_auth_data_facebook_id: { '_auth_data_facebook.id': 1 },
_auth_data_myoauth_id: { '_auth_data_myoauth.id': 1 },
_auth_data_shortLivedAuth_id: { '_auth_data_shortLivedAuth.id': 1 },
_auth_data_anonymous_id: { '_auth_data_anonymous.id': 1 },
});
}
);
it_only_db('mongo')(
'should use _email_verify_token index in email verification',
async () => {
const TestUtils = require('../lib/TestUtils');
let emailVerificationLink;
const emailSentPromise = TestUtils.resolvingPromise();
const emailAdapter = {
sendVerificationEmail: options => {
emailVerificationLink = options.link;
emailSentPromise.resolve();
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {},
};
await reconfigureServer({
databaseURI: 'mongodb://localhost:27017/testEmailVerifyTokenIndexStats',
databaseAdapter: undefined,
appName: 'test',
verifyUserEmails: true,
emailAdapter: emailAdapter,
publicServerURL: 'http://localhost:8378/1',
});
// Create a user to trigger email verification
const user = new Parse.User();
user.setUsername('statsuser');
user.setPassword('password');
user.set('email', 'stats@example.com');
await user.signUp();
await emailSentPromise;
// Get index stats before the query
const config = Config.get(Parse.applicationId);
const collection = await config.database.adapter._adaptiveCollection('_User');
const statsBefore = await collection._mongoCollection.aggregate([
{ $indexStats: {} },
]).toArray();
const emailVerifyIndexBefore = statsBefore.find(
stat => stat.name === '_email_verify_token'
);
const accessesBefore = emailVerifyIndexBefore?.accesses?.ops || 0;
// Perform email verification (this should use the index)
const request = require('../lib/request');
await request({
url: emailVerificationLink,
followRedirects: false,
});
// Get index stats after the query
const statsAfter = await collection._mongoCollection.aggregate([
{ $indexStats: {} },
]).toArray();
const emailVerifyIndexAfter = statsAfter.find(
stat => stat.name === '_email_verify_token'
);
const accessesAfter = emailVerifyIndexAfter?.accesses?.ops || 0;
// Verify the index was actually used
expect(accessesAfter).toBeGreaterThan(accessesBefore);
expect(emailVerifyIndexAfter).toBeDefined();
// Verify email verification succeeded
await user.fetch();
expect(user.get('emailVerified')).toBe(true);
}
);
it_only_db('mongo')(
'should use _perishable_token index in password reset',
async () => {
const TestUtils = require('../lib/TestUtils');
let passwordResetLink;
const emailSentPromise = TestUtils.resolvingPromise();
const emailAdapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: options => {
passwordResetLink = options.link;
emailSentPromise.resolve();
},
sendMail: () => {},
};
await reconfigureServer({
databaseURI: 'mongodb://localhost:27017/testPerishableTokenIndexStats',
databaseAdapter: undefined,
appName: 'test',
emailAdapter: emailAdapter,
publicServerURL: 'http://localhost:8378/1',
});
// Create a user
const user = new Parse.User();
user.setUsername('statsuser2');
user.setPassword('oldpassword');
user.set('email', 'stats2@example.com');
await user.signUp();
// Request password reset
await Parse.User.requestPasswordReset('stats2@example.com');
await emailSentPromise;
const url = new URL(passwordResetLink);
const token = url.searchParams.get('token');
// Get index stats before the query
const config = Config.get(Parse.applicationId);
const collection = await config.database.adapter._adaptiveCollection('_User');
const statsBefore = await collection._mongoCollection.aggregate([
{ $indexStats: {} },
]).toArray();
const perishableTokenIndexBefore = statsBefore.find(
stat => stat.name === '_perishable_token'
);
const accessesBefore = perishableTokenIndexBefore?.accesses?.ops || 0;
// Perform password reset (this should use the index)
const request = require('../lib/request');
await request({
method: 'POST',
url: 'http://localhost:8378/1/apps/test/request_password_reset',
body: { new_password: 'newpassword', token, username: 'statsuser2' },
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
followRedirects: false,
});
// Get index stats after the query
const statsAfter = await collection._mongoCollection.aggregate([
{ $indexStats: {} },
]).toArray();
const perishableTokenIndexAfter = statsAfter.find(
stat => stat.name === '_perishable_token'
);
const accessesAfter = perishableTokenIndexAfter?.accesses?.ops || 0;
// Verify the index was actually used
expect(accessesAfter).toBeGreaterThan(accessesBefore);
expect(perishableTokenIndexAfter).toBeDefined();
}
);
});
describe('convertEmailToLowercase', () => {
@@ -615,6 +771,76 @@ describe('DatabaseController', function () {
expect(result2.length).toEqual(1);
});
});
describe('update with validateOnly', () => {
const mockStorageAdapter = {
findOneAndUpdate: () => Promise.resolve({}),
find: () => Promise.resolve([{ objectId: 'test123', testField: 'initialValue' }]),
watch: () => Promise.resolve(),
getAllClasses: () =>
Promise.resolve([
{
className: 'TestObject',
fields: { testField: 'String' },
indexes: {},
classLevelPermissions: { protectedFields: {} },
},
]),
};
it('should use primary readPreference when validateOnly is true', async () => {
const databaseController = new DatabaseController(mockStorageAdapter, {});
const findSpy = spyOn(mockStorageAdapter, 'find').and.callThrough();
const findOneAndUpdateSpy = spyOn(mockStorageAdapter, 'findOneAndUpdate').and.callThrough();
try {
// Call update with validateOnly: true (same as RestWrite.runBeforeSaveTrigger)
await databaseController.update(
'TestObject',
{ objectId: 'test123' },
{ testField: 'newValue' },
{},
true, // skipSanitization: true (matches RestWrite behavior)
true // validateOnly: true
);
} catch (error) {
// validateOnly may throw, but we're checking the find call options
}
// Verify that find was called with primary readPreference
expect(findSpy).toHaveBeenCalled();
const findCall = findSpy.calls.mostRecent();
expect(findCall.args[3]).toEqual({ readPreference: 'primary' }); // options parameter
// Verify that findOneAndUpdate was NOT called (only validation, no actual update)
expect(findOneAndUpdateSpy).not.toHaveBeenCalled();
});
it('should not use primary readPreference when validateOnly is false', async () => {
const databaseController = new DatabaseController(mockStorageAdapter, {});
const findSpy = spyOn(mockStorageAdapter, 'find').and.callThrough();
const findOneAndUpdateSpy = spyOn(mockStorageAdapter, 'findOneAndUpdate').and.callThrough();
try {
// Call update with validateOnly: false
await databaseController.update(
'TestObject',
{ objectId: 'test123' },
{ testField: 'newValue' },
{},
false, // skipSanitization
false // validateOnly
);
} catch (error) {
// May throw for other reasons, but we're checking the call pattern
}
// When validateOnly is false, find should not be called for validation
// Instead, findOneAndUpdate should be called
expect(findSpy).not.toHaveBeenCalled();
expect(findOneAndUpdateSpy).toHaveBeenCalled();
});
});
});
function buildCLP(pointerNames) {
+50 -2
View File
@@ -371,7 +371,7 @@ describe('DefinedSchemas', () => {
expect(schema.indexes).toEqual(indexes);
});
it('should delete removed indexes', async () => {
it('should delete unknown indexes when keepUnknownIndexes is not set', async () => {
const server = await reconfigureServer();
let indexes = { complex: { createdAt: 1, updatedAt: 1 } };
@@ -393,6 +393,53 @@ describe('DefinedSchemas', () => {
cleanUpIndexes(schema);
expect(schema.indexes).toBeUndefined();
});
it('should delete unknown indexes when keepUnknownIndexes is set to false', async () => {
const server = await reconfigureServer();
let indexes = { complex: { createdAt: 1, updatedAt: 1 } };
let schemas = { definitions: [{ className: 'Test', indexes }], keepUnknownIndexes: false };
await new DefinedSchemas(schemas, server.config).execute();
indexes = {};
schemas = { definitions: [{ className: 'Test', indexes }], keepUnknownIndexes: false };
// Change indexes
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toBeUndefined();
// Update
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toBeUndefined();
});
it('should not delete unknown indexes when keepUnknownIndexes is set to true', async () => {
const server = await reconfigureServer();
const indexes = { complex: { createdAt: 1, updatedAt: 1 } };
let schemas = { definitions: [{ className: 'Test', indexes }], keepUnknownIndexes: true };
await new DefinedSchemas(schemas, server.config).execute();
schemas = { definitions: [{ className: 'Test', indexes: {} }], keepUnknownIndexes: true };
// Change indexes
await new DefinedSchemas(schemas, server.config).execute();
let schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toEqual({ complex: { createdAt: 1, updatedAt: 1 } });
// Update
await new DefinedSchemas(schemas, server.config).execute();
schema = await new Parse.Schema('Test').get();
cleanUpIndexes(schema);
expect(schema.indexes).toEqual(indexes);
});
xit('should keep protected indexes', async () => {
const server = await reconfigureServer();
@@ -642,7 +689,8 @@ describe('DefinedSchemas', () => {
expect(logger.error).toHaveBeenCalledWith(`Failed to run migrations: ${error.toString()}`);
});
it('should perform migration in parallel without failing', async () => {
it_id('a18bf4f2-25c8-4de3-b986-19cb1ab163b8')(it)('should perform migration in parallel without failing', async () => {
const server = await reconfigureServer();
const logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callThrough();
+25
View File
@@ -45,4 +45,29 @@ describe('Deprecator', () => {
`DeprecationWarning: ${options.usage} is deprecated and will be removed in a future version. ${options.solution}`
);
});
it('logs deprecation for nested option key with dot notation', async () => {
deprecations = [{ optionKey: 'databaseOptions.allowPublicExplain', changeNewDefault: 'false' }];
spyOn(Deprecator, '_getDeprecations').and.callFake(() => deprecations);
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'warn').and.callFake(() => {});
await reconfigureServer();
expect(logSpy.calls.all()[0].args[0]).toEqual(
`DeprecationWarning: The Parse Server option '${deprecations[0].optionKey}' default will change to '${deprecations[0].changeNewDefault}' in a future version.`
);
});
it('does not log deprecation for nested option key if option is set manually', async () => {
deprecations = [{ optionKey: 'databaseOptions.allowPublicExplain', changeNewDefault: 'false' }];
spyOn(Deprecator, '_getDeprecations').and.callFake(() => deprecations);
const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {});
const Config = require('../lib/Config');
const config = Config.get('test');
// Directly test scanParseServerOptions with nested option set
Deprecator.scanParseServerOptions({ databaseOptions: { allowPublicExplain: true } });
expect(logSpy).not.toHaveBeenCalled();
});
});
File diff suppressed because it is too large Load Diff
+3 -5
View File
@@ -3,11 +3,9 @@ const request = require('../lib/request');
describe('Enable express error handler', () => {
it('should call the default handler in case of error, like updating a non existing object', async done => {
spyOn(console, 'error');
const parseServer = await reconfigureServer(
Object.assign({}, defaultConfiguration, {
enableExpressErrorHandler: true,
})
);
const parseServer = await reconfigureServer({
enableExpressErrorHandler: true,
});
parseServer.app.use(function (err, req, res, next) {
expect(err.message).toBe('Object not found.');
next(err);
+69 -13
View File
@@ -21,11 +21,14 @@ const mockAdapter = {
// Small additional tests to improve overall coverage
describe('FilesController', () => {
it('should properly expand objects', done => {
it('should properly expand objects with sync getFileLocation', async () => {
const config = Config.get(Parse.applicationId);
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
gridFSAdapter.getFileLocation = (config, filename) => {
return config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename);
}
const filesController = new FilesController(gridFSAdapter);
const result = filesController.expandFilesInObject(config, function () {});
const result = await filesController.expandFilesInObject(config, function () { });
expect(result).toBeUndefined();
@@ -37,12 +40,69 @@ describe('FilesController', () => {
const anObject = {
aFile: fullFile,
};
filesController.expandFilesInObject(config, anObject);
await filesController.expandFilesInObject(config, anObject);
expect(anObject.aFile.url).toEqual('http://an.url');
done();
});
it('should properly expand objects with async getFileLocation', async () => {
const config = Config.get(Parse.applicationId);
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
gridFSAdapter.getFileLocation = async (config, filename) => {
await Promise.resolve();
return config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename);
}
const filesController = new FilesController(gridFSAdapter);
const result = await filesController.expandFilesInObject(config, function () { });
expect(result).toBeUndefined();
const fullFile = {
type: '__type',
url: 'http://an.url',
};
const anObject = {
aFile: fullFile,
};
await filesController.expandFilesInObject(config, anObject);
expect(anObject.aFile.url).toEqual('http://an.url');
});
it('should call getFileLocation when config.fileKey is undefined', async () => {
const config = {};
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const fullFile = {
name: 'mock-name',
__type: 'File',
};
gridFSAdapter.getFileLocation = jasmine.createSpy('getFileLocation').and.returnValue(Promise.resolve('mock-url'));
const filesController = new FilesController(gridFSAdapter);
const anObject = { aFile: fullFile };
await filesController.expandFilesInObject(config, anObject);
expect(gridFSAdapter.getFileLocation).toHaveBeenCalledWith(config, fullFile.name);
expect(anObject.aFile.url).toEqual('mock-url');
});
it('should call getFileLocation when config.fileKey is defined', async () => {
const config = { fileKey: 'mock-key' };
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
const fullFile = {
name: 'mock-name',
__type: 'File',
};
gridFSAdapter.getFileLocation = jasmine.createSpy('getFileLocation').and.returnValue(Promise.resolve('mock-url'));
const filesController = new FilesController(gridFSAdapter);
const anObject = { aFile: fullFile };
await filesController.expandFilesInObject(config, anObject);
expect(gridFSAdapter.getFileLocation).toHaveBeenCalledWith(config, fullFile.name);
expect(anObject.aFile.url).toEqual('mock-url');
});
it_only_db('mongo')('should pass databaseOptions to GridFSBucketAdapter', async () => {
await reconfigureServer({
databaseURI: 'mongodb://localhost:27017/parse',
@@ -101,7 +161,7 @@ describe('FilesController', () => {
done();
});
it('should add a unique hash to the file name when the preserveFileName option is false', done => {
it('should add a unique hash to the file name when the preserveFileName option is false', async () => {
const config = Config.get(Parse.applicationId);
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
spyOn(gridFSAdapter, 'createFile');
@@ -112,17 +172,15 @@ describe('FilesController', () => {
preserveFileName: false,
});
filesController.createFile(config, fileName);
await filesController.createFile(config, fileName);
expect(gridFSAdapter.createFile).toHaveBeenCalledTimes(1);
expect(gridFSAdapter.createFile.calls.mostRecent().args[0]).toMatch(
`^.{32}_${regexEscapedFileName}$`
);
done();
});
it('should not add a unique hash to the file name when the preserveFileName option is true', done => {
it('should not add a unique hash to the file name when the preserveFileName option is true', async () => {
const config = Config.get(Parse.applicationId);
const gridFSAdapter = new GridFSBucketAdapter('mongodb://localhost:27017/parse');
spyOn(gridFSAdapter, 'createFile');
@@ -132,12 +190,10 @@ describe('FilesController', () => {
preserveFileName: true,
});
filesController.createFile(config, fileName);
await filesController.createFile(config, fileName);
expect(gridFSAdapter.createFile).toHaveBeenCalledTimes(1);
expect(gridFSAdapter.createFile.calls.mostRecent().args[0]).toEqual(fileName);
done();
});
it('should handle adapter without getMetadata', async () => {
+181
View File
@@ -0,0 +1,181 @@
'use strict';
const http = require('http');
const express = require('express');
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
require('./helper');
const { ParseGraphQLServer } = require('../lib/GraphQL/ParseGraphQLServer');
describe('graphql query complexity', () => {
let httpServer;
let graphQLServer;
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'Content-Type': 'application/json',
};
async function setupGraphQL(serverOptions = {}) {
if (httpServer) {
await new Promise(resolve => httpServer.close(resolve));
}
const server = await reconfigureServer(serverOptions);
const expressApp = express();
httpServer = http.createServer(expressApp);
expressApp.use('/parse', server.app);
graphQLServer = new ParseGraphQLServer(server, {
graphQLPath: '/graphql',
});
graphQLServer.applyGraphQL(expressApp);
await new Promise(resolve => httpServer.listen({ port: 13378 }, resolve));
}
async function graphqlRequest(query, requestHeaders = headers) {
const response = await fetch('http://localhost:13378/graphql', {
method: 'POST',
headers: requestHeaders,
body: JSON.stringify({ query }),
});
return response.json();
}
// Returns a query with depth 4: users(1) > edges(2) > node(3) > objectId(4)
function buildDeepQuery() {
return '{ users { edges { node { objectId } } } }';
}
function buildWideQuery(fieldCount) {
const fields = Array.from({ length: fieldCount }, (_, i) => `field${i}: objectId`).join('\n ');
return `{ users { edges { node { ${fields} } } } }`;
}
afterEach(async () => {
if (httpServer) {
await new Promise(resolve => httpServer.close(resolve));
httpServer = null;
}
});
describe('depth limit', () => {
it('should reject query exceeding depth limit', async () => {
await setupGraphQL({
requestComplexity: { graphQLDepth: 3 },
});
const result = await graphqlRequest(buildDeepQuery());
expect(result.errors).toBeDefined();
expect(result.errors[0].message).toMatch(
/GraphQL query depth of \d+ exceeds maximum allowed depth of 3/
);
});
it('should allow query within depth limit', async () => {
await setupGraphQL({
requestComplexity: { graphQLDepth: 10 },
});
const result = await graphqlRequest(buildDeepQuery());
expect(result.errors).toBeUndefined();
});
it('should allow deep query with master key', async () => {
await setupGraphQL({
requestComplexity: { graphQLDepth: 3 },
});
const result = await graphqlRequest(buildDeepQuery(), {
...headers,
'X-Parse-Master-Key': 'test',
});
expect(result.errors).toBeUndefined();
});
it('should allow unlimited depth when graphQLDepth is -1', async () => {
await setupGraphQL({
requestComplexity: { graphQLDepth: -1 },
});
const result = await graphqlRequest(buildDeepQuery());
expect(result.errors).toBeUndefined();
});
});
describe('fields limit', () => {
it('should reject query exceeding fields limit', async () => {
await setupGraphQL({
requestComplexity: { graphQLFields: 5 },
});
const result = await graphqlRequest(buildWideQuery(10));
expect(result.errors).toBeDefined();
expect(result.errors[0].message).toMatch(
/Number of GraphQL fields \(\d+\) exceeds maximum allowed \(5\)/
);
});
it('should allow query within fields limit', async () => {
await setupGraphQL({
requestComplexity: { graphQLFields: 200 },
});
const result = await graphqlRequest(buildDeepQuery());
expect(result.errors).toBeUndefined();
});
it('should allow wide query with master key', async () => {
await setupGraphQL({
requestComplexity: { graphQLFields: 5 },
});
const result = await graphqlRequest(buildWideQuery(10), {
...headers,
'X-Parse-Master-Key': 'test',
});
expect(result.errors).toBeUndefined();
});
it('should count fragment fields at each spread location', async () => {
// With correct counting: 2 aliases (2) + 2×edges (2) + 2×node (2) + 2×objectId from fragment (2) = 8
// With incorrect counting (fragment once): 2 + 2 + 2 + 1 = 7
// Set limit to 7 so incorrect counting passes but correct counting rejects
await setupGraphQL({
requestComplexity: { graphQLFields: 7 },
});
const result = await graphqlRequest(`
fragment UserFields on User { objectId }
{
a1: users { edges { node { ...UserFields } } }
a2: users { edges { node { ...UserFields } } }
}
`);
expect(result.errors).toBeDefined();
expect(result.errors[0].message).toMatch(
/Number of GraphQL fields \(\d+\) exceeds maximum allowed \(7\)/
);
});
it('should count inline fragment fields toward depth and field limits', async () => {
await setupGraphQL({
requestComplexity: { graphQLFields: 3 },
});
// Inline fragment adds fields without increasing depth:
// users(1) > edges(2) > ... on UserConnection { edges(3) > node(4) }
const result = await graphqlRequest(`{
users {
edges {
... on UserEdge {
node {
objectId
}
}
}
}
}`);
expect(result.errors).toBeDefined();
expect(result.errors[0].message).toMatch(
/Number of GraphQL fields \(\d+\) exceeds maximum allowed \(3\)/
);
});
it('should allow unlimited fields when graphQLFields is -1', async () => {
await setupGraphQL({
requestComplexity: { graphQLFields: -1 },
});
const result = await graphqlRequest(buildWideQuery(50));
expect(result.errors).toBeUndefined();
});
});
});
+19 -1
View File
@@ -24,10 +24,20 @@ describe_only_db('mongo')('GridFSBucket', () => {
const databaseURI = 'mongodb://localhost:27017/parse';
const gfsAdapter = new GridFSBucketAdapter(databaseURI, {
retryWrites: true,
// these are not supported by the mongo client
// Parse Server-specific options that should be filtered out before passing to MongoDB client
allowPublicExplain: true,
enableSchemaHooks: true,
schemaCacheTtl: 5000,
maxTimeMS: 30000,
disableIndexFieldValidation: true,
logClientEvents: [{ name: 'commandStarted' }],
createIndexUserUsername: true,
createIndexUserUsernameCaseInsensitive: true,
createIndexUserEmail: true,
createIndexUserEmailCaseInsensitive: true,
createIndexUserEmailVerifyToken: true,
createIndexUserPasswordResetToken: true,
createIndexRoleName: true,
});
const db = await gfsAdapter._connect();
@@ -421,6 +431,14 @@ describe_only_db('mongo')('GridFSBucket', () => {
expect(gfsResult.toString('utf8')).toBe(twoMegabytesFile);
});
it('properly upload a file when disableIndexFieldValidation exist in databaseOptions', async () => {
const gfsAdapter = new GridFSBucketAdapter(databaseURI, { disableIndexFieldValidation: true });
const twoMegabytesFile = randomString(2048 * 1024);
await gfsAdapter.createFile('myFileName', twoMegabytesFile);
const gfsResult = await gfsAdapter.getFileData('myFileName');
expect(gfsResult.toString('utf8')).toBe(twoMegabytesFile);
});
it('properly deletes a file from GridFS', async () => {
const gfsAdapter = new GridFSBucketAdapter(databaseURI);
await gfsAdapter.createFile('myFileName', 'a simple file');
+1 -2
View File
@@ -2,7 +2,6 @@
const httpRequest = require('../lib/request'),
HTTPResponse = require('../lib/request').HTTPResponse,
bodyParser = require('body-parser'),
express = require('express');
const port = 13371;
@@ -10,7 +9,7 @@ const httpRequestServer = `http://localhost:${port}`;
function startServer(done) {
const app = express();
app.use(bodyParser.json({ type: '*/*' }));
app.use(express.json({ type: '*/*' }));
app.get('/hello', function (req, res) {
res.json({ response: 'OK' });
});
+12 -8
View File
@@ -45,8 +45,12 @@ describe('Idempotency', () => {
});
});
afterEach(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000;
});
// Tests
it('should enforce idempotency for cloud code function', async () => {
it_id('e25955fd-92eb-4b22-b8b7-38980e5cb223')(it)('should enforce idempotency for cloud code function', async () => {
let counter = 0;
Parse.Cloud.define('myFunction', () => {
counter++;
@@ -69,7 +73,7 @@ describe('Idempotency', () => {
expect(counter).toBe(1);
});
it('should delete request entry after TTL', async () => {
it_id('be2fbe16-8178-485e-9a12-6fb541096480')(it)('should delete request entry after TTL', async () => {
let counter = 0;
Parse.Cloud.define('myFunction', () => {
counter++;
@@ -119,7 +123,7 @@ describe('Idempotency', () => {
}
);
it('should enforce idempotency for cloud code jobs', async () => {
it_id('e976d0cc-a57f-45d4-9472-b9b052db6490')(it)('should enforce idempotency for cloud code jobs', async () => {
let counter = 0;
Parse.Cloud.job('myJob', () => {
counter++;
@@ -141,7 +145,7 @@ describe('Idempotency', () => {
expect(counter).toBe(1);
});
it('should enforce idempotency for class object creation', async () => {
it_id('7c84a3d4-e1b6-4a0d-99f1-af3cf1a6b3d8')(it)('should enforce idempotency for class object creation', async () => {
let counter = 0;
Parse.Cloud.afterSave('MyClass', () => {
counter++;
@@ -163,7 +167,7 @@ describe('Idempotency', () => {
expect(counter).toBe(1);
});
it('should enforce idempotency for user object creation', async () => {
it_id('a030f2dd-5d21-46ac-b53d-9d714f35d72a')(it)('should enforce idempotency for user object creation', async () => {
let counter = 0;
Parse.Cloud.afterSave('_User', () => {
counter++;
@@ -189,7 +193,7 @@ describe('Idempotency', () => {
expect(counter).toBe(1);
});
it('should enforce idempotency for installation object creation', async () => {
it_id('064c469b-091c-4ba9-9043-be461f26a3eb')(it)('should enforce idempotency for installation object creation', async () => {
let counter = 0;
Parse.Cloud.afterSave('_Installation', () => {
counter++;
@@ -215,7 +219,7 @@ describe('Idempotency', () => {
expect(counter).toBe(1);
});
it('should not interfere with calls of different request ID', async () => {
it_id('f11670b6-fa9c-4f21-a268-ae4b6bbff7fd')(it)('should not interfere with calls of different request ID', async () => {
let counter = 0;
Parse.Cloud.afterSave('MyClass', () => {
counter++;
@@ -236,7 +240,7 @@ describe('Idempotency', () => {
expect(counter).toBe(100);
});
it('should re-throw any other error unchanged when writing request entry fails for any other reason', async () => {
it_id('0ecd2cd2-dafb-4a2b-bb2b-9ad4c9aca777')(it)('should re-throw any other error unchanged when writing request entry fails for any other reason', async () => {
spyOn(rest, 'create').and.rejectWith(new Parse.Error(0, 'some other error'));
Parse.Cloud.define('myFunction', () => {});
const params = {
+172
View File
@@ -4,6 +4,178 @@ const fs = require('fs');
const port = 12345;
const sslport = 12346;
describe('LDAP Injection Prevention', () => {
describe('escapeDN', () => {
it('should escape comma', () => {
expect(ldap.escapeDN('admin,ou=evil')).toBe('admin\\,ou\\=evil');
});
it('should escape equals sign', () => {
expect(ldap.escapeDN('admin=evil')).toBe('admin\\=evil');
});
it('should escape plus sign', () => {
expect(ldap.escapeDN('admin+evil')).toBe('admin\\+evil');
});
it('should escape less-than and greater-than signs', () => {
expect(ldap.escapeDN('admin<evil>')).toBe('admin\\<evil\\>');
});
it('should escape hash at start', () => {
expect(ldap.escapeDN('#admin')).toBe('\\#admin');
});
it('should escape semicolon', () => {
expect(ldap.escapeDN('admin;evil')).toBe('admin\\;evil');
});
it('should escape double quote', () => {
expect(ldap.escapeDN('admin"evil')).toBe('admin\\"evil');
});
it('should escape backslash', () => {
expect(ldap.escapeDN('admin\\evil')).toBe('admin\\\\evil');
});
it('should escape leading space', () => {
expect(ldap.escapeDN(' admin')).toBe('\\ admin');
});
it('should escape trailing space', () => {
expect(ldap.escapeDN('admin ')).toBe('admin\\ ');
});
it('should escape multiple special characters', () => {
expect(ldap.escapeDN('admin,ou=evil+cn=x')).toBe('admin\\,ou\\=evil\\+cn\\=x');
});
it('should not modify safe values', () => {
expect(ldap.escapeDN('testuser')).toBe('testuser');
expect(ldap.escapeDN('john.doe')).toBe('john.doe');
expect(ldap.escapeDN('user123')).toBe('user123');
});
});
describe('escapeFilter', () => {
it('should escape asterisk', () => {
expect(ldap.escapeFilter('*')).toBe('\\2a');
});
it('should escape open parenthesis', () => {
expect(ldap.escapeFilter('test(')).toBe('test\\28');
});
it('should escape close parenthesis', () => {
expect(ldap.escapeFilter('test)')).toBe('test\\29');
});
it('should escape backslash', () => {
expect(ldap.escapeFilter('test\\')).toBe('test\\5c');
});
it('should escape null byte', () => {
expect(ldap.escapeFilter('test\x00')).toBe('test\\00');
});
it('should escape multiple special characters', () => {
expect(ldap.escapeFilter('*()\\')).toBe('\\2a\\28\\29\\5c');
});
it('should not modify safe values', () => {
expect(ldap.escapeFilter('testuser')).toBe('testuser');
expect(ldap.escapeFilter('john.doe')).toBe('john.doe');
expect(ldap.escapeFilter('user123')).toBe('user123');
});
it('should escape filter injection attempt with wildcard', () => {
expect(ldap.escapeFilter('x)(|(objectClass=*)')).toBe('x\\29\\28|\\28objectClass=\\2a\\29');
});
});
describe('authData validation', () => {
it('should reject missing authData.id', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
try {
await ldap.validateAuthData({ password: 'secret' }, options);
fail('Should have rejected missing id');
} catch (err) {
expect(err.message).toBe('LDAP: Wrong username or password');
}
server.close(done);
});
it('should reject non-string authData.id', async done => {
const server = await mockLdapServer(port, 'uid=testuser, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
try {
await ldap.validateAuthData({ id: 123, password: 'secret' }, options);
fail('Should have rejected non-string id');
} catch (err) {
expect(err.message).toBe('LDAP: Wrong username or password');
}
server.close(done);
});
});
describe('DN injection prevention', () => {
it('should prevent DN injection via comma in authData.id', async done => {
// Mock server accepts the DN that would result from an unescaped injection
const server = await mockLdapServer(port, 'uid=admin,ou=admins,o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
};
// Attacker tries to inject additional DN components via comma
// Without escaping: DN = uid=admin,ou=admins, o=example (3 RDNs) → matches mock
// With escaping: DN = uid=admin\,ou=admins, o=example (2 RDNs) → doesn't match
try {
await ldap.validateAuthData({ id: 'admin,ou=admins', password: 'secret' }, options);
fail('Should have rejected DN injection attempt');
} catch (err) {
expect(err.message).toBe('LDAP: Wrong username or password');
}
server.close(done);
});
});
describe('Filter injection prevention', () => {
it('should prevent LDAP filter injection via wildcard in authData.id', async done => {
// Mock server accepts uid=*, o=example (the attacker's bind DN)
// The * is not special in DNs so it binds fine regardless of escaping
const server = await mockLdapServer(port, 'uid=*, o=example');
const options = {
suffix: 'o=example',
url: `ldap://localhost:${port}`,
dn: 'uid={{id}}, o=example',
groupCn: 'powerusers',
groupFilter: '(&(uniqueMember=uid={{id}}, o=example)(objectClass=groupOfUniqueNames))',
};
// Attacker uses * as ID to match any group member via wildcard
// Group has member uid=testuser, not uid=*
// Without escaping: filter uses SubstringFilter, matches testuser → passes
// With escaping: filter uses EqualityFilter with literal \2a, no match → fails
try {
await ldap.validateAuthData({ id: '*', password: 'secret' }, options);
fail('Should have rejected filter injection attempt');
} catch (err) {
expect(err.message).toBe('LDAP: User not in group');
}
server.close(done);
});
});
});
describe('Ldap Auth', () => {
it('Should fail with missing options', done => {
ldap
+8 -4
View File
@@ -52,6 +52,9 @@ describe_only(() => {
});
it('can check invalid master key of request', done => {
const logger = require('../lib/logger').default;
const loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
loggerErrorSpy.calls.reset();
request({
url: 'http://localhost:8378/1/scriptlog',
headers: {
@@ -61,7 +64,8 @@ describe_only(() => {
}).then(fail, response => {
const body = response.data;
expect(response.status).toEqual(403);
expect(body.error).toEqual('unauthorized: master key is required');
expect(body.error).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
});
});
@@ -75,7 +79,7 @@ describe_only(() => {
/**
* Verifies simple passwords in GET login requests with special characters are scrubbed from the verbose log
*/
it('does scrub simple passwords on GET login', done => {
it_id('e36d6141-2a20-41d0-85fc-d1534c3e4bae')(it)('does scrub simple passwords on GET login', done => {
reconfigureServer({
verbose: true,
}).then(function () {
@@ -105,7 +109,7 @@ describe_only(() => {
/**
* Verifies complex passwords in GET login requests with special characters are scrubbed from the verbose log
*/
it('does scrub complex passwords on GET login', done => {
it_id('24b277c5-250f-4a35-a449-2c8c519d4c03')(it)('does scrub complex passwords on GET login', done => {
reconfigureServer({
verbose: true,
})
@@ -139,7 +143,7 @@ describe_only(() => {
/**
* Verifies fields in POST login requests are NOT present in the verbose log
*/
it('does not have password field in POST login', done => {
it_id('33143ec9-b32d-467c-ba65-ff2bbefdaadd')(it)('does not have password field in POST login', done => {
reconfigureServer({
verbose: true,
}).then(function () {
+25 -27
View File
@@ -32,7 +32,10 @@ describe('middlewares', () => {
AppCache.del(fakeReq.body._ApplicationId);
});
it('should use _ContentType if provided', done => {
it_id('4cc18d90-1763-4725-97fa-f63fb4692fc4')(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;
@@ -43,32 +46,32 @@ describe('middlewares', () => {
});
});
it('should give invalid response when keys are configured but no key supplied', () => {
it('should give invalid response when keys are configured but no key supplied', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
});
middlewares.handleParseHeaders(fakeReq, fakeRes);
await middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
it('should give invalid response when keys are configured but supplied key is incorrect', () => {
it('should give invalid response when keys are configured but supplied key is incorrect', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
});
fakeReq.headers['x-parse-rest-api-key'] = 'wrongKey';
middlewares.handleParseHeaders(fakeReq, fakeRes);
await middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
it('should give invalid response when keys are configured but different key is supplied', () => {
it('should give invalid response when keys are configured but different key is supplied', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
restAPIKey: 'restAPIKey',
});
fakeReq.headers['x-parse-client-key'] = 'clientKey';
middlewares.handleParseHeaders(fakeReq, fakeRes);
await middlewares.handleParseHeaders(fakeReq, fakeRes);
expect(fakeRes.status).toHaveBeenCalledWith(403);
});
@@ -125,7 +128,7 @@ describe('middlewares', () => {
const otherKeys = BodyKeys.filter(
otherKey => otherKey !== infoKey && otherKey !== 'javascriptKey'
);
it(`it should pull ${bodyKey} into req.info`, done => {
it_id('f9abd7ac-b1f4-4607-b9b0-365ff0559d84')(it)(`it should pull ${bodyKey} into req.info`, done => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKeyIps: ['0.0.0.0/0'],
});
@@ -144,7 +147,7 @@ describe('middlewares', () => {
});
});
it('should not succeed and log if the ip does not belong to masterKeyIps list', async () => {
it_id('4a0bce41-c536-4482-a873-12ed023380e2')(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, {
@@ -153,25 +156,17 @@ describe('middlewares', () => {
});
fakeReq.ip = '127.0.0.1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
expect(fakeReq.auth.isMaster).toBe(false);
const error = await middlewares.handleParseHeaders(fakeReq, fakeRes, () => {}).catch(e => e);
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 not succeed if the ip does not belong to masterKeyIps list', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['10.0.0.1'],
});
fakeReq.ip = '127.0.0.1';
fakeReq.headers['x-parse-master-key'] = 'masterKey';
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
expect(fakeReq.auth.isMaster).toBe(false);
});
it('should not succeed if the ip does not belong to maintenanceKeyIps list', async () => {
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, {
@@ -180,14 +175,17 @@ describe('middlewares', () => {
});
fakeReq.ip = '10.0.0.2';
fakeReq.headers['x-parse-maintenance-key'] = 'masterKey';
await new Promise(resolve => middlewares.handleParseHeaders(fakeReq, fakeRes, resolve));
expect(fakeReq.auth.isMaintenance).toBe(false);
const error = await middlewares.handleParseHeaders(fakeReq, fakeRes, () => {}).catch(e => e);
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 succeed if the ip does belong to masterKeyIps list', async () => {
it_id('2f7fadec-a87c-4626-90d1-65c75653aea9')(it)('should succeed if the ip does belong to masterKeyIps list', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['10.0.0.1'],
@@ -198,7 +196,7 @@ describe('middlewares', () => {
expect(fakeReq.auth.isMaster).toBe(true);
});
it('should allow any ip to use masterKey if masterKeyIps is empty', async () => {
it_id('2b251fd4-d43c-48f4-ada9-c8458e40c12a')(it)('should allow any ip to use masterKey if masterKeyIps is empty', async () => {
AppCachePut(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
masterKeyIps: ['0.0.0.0/0'],
+12
View File
@@ -18,6 +18,12 @@ describe('MongoSchemaCollection', () => {
},
_metadata: {
class_permissions: {
ACL: {
'*': {
read: true,
write: true,
},
},
get: { '*': true },
find: { '*': true },
count: { '*': true },
@@ -69,6 +75,12 @@ describe('MongoSchemaCollection', () => {
objectId: { type: 'String' },
},
classLevelPermissions: {
ACL: {
'*': {
read: true,
write: true,
},
},
find: { '*': true },
get: { '*': true },
count: { '*': true },
+420 -54
View File
@@ -15,8 +15,8 @@ const fakeClient = {
// These tests are specific to the mongo storage adapter + mongo storage format
// and will eventually be moved into their own repo
describe_only_db('mongo')('MongoStorageAdapter', () => {
beforeEach(done => {
new MongoStorageAdapter({ uri: databaseURI }).deleteAllClasses().then(done, fail);
beforeEach(async () => {
await new MongoStorageAdapter({ uri: databaseURI }).deleteAllClasses();
Config.get(Parse.applicationId).schemaCache.clear();
});
@@ -284,25 +284,11 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
amount: 1,
},
};
await Parse.Server.database.update(
'MyClass',
query,
update,
{ upsert: true },
);
await Parse.Server.database.update('MyClass', query, update, { upsert: true });
update.objectId.amount = uuid2;
await Parse.Server.database.update(
'MyClass',
query,
update,
{ upsert: true },
);
await Parse.Server.database.update('MyClass', query, update, { upsert: true });
const res = await Parse.Server.database.find(
schema.className,
{},
{},
);
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);
@@ -404,7 +390,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await expectAsync(adapter.getClass('UnknownClass')).toBeRejectedWith(undefined);
});
it_only_mongodb_version('<5.1>=6')('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');
@@ -438,40 +424,6 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
expect(postIndexPlan.executionStats.executionStages.stage).toBe('FETCH');
});
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');
await user.signUp();
const database = Config.get(Parse.applicationId).database;
await database.adapter.dropAllIndexes('_User');
const preIndexPlan = await database.find(
'_User',
{ username: 'bugs' },
{ caseInsensitive: true, explain: true }
);
const schema = await new Parse.Schema('_User').get();
await database.adapter.ensureIndex(
'_User',
schema,
['username'],
'case_insensitive_username',
true
);
const postIndexPlan = await database.find(
'_User',
{ username: 'bugs' },
{ caseInsensitive: true, explain: true }
);
expect(preIndexPlan.queryPlanner.winningPlan.queryPlan.stage).toBe('COLLSCAN');
expect(postIndexPlan.queryPlanner.winningPlan.queryPlan.stage).toBe('FETCH');
});
it('should delete field without index', async () => {
const database = Config.get(Parse.applicationId).database;
const obj = new Parse.Object('MyObject');
@@ -697,4 +649,418 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
});
}
describe('index creation options', () => {
beforeEach(async () => {
await new MongoStorageAdapter({ uri: databaseURI }).deleteAllClasses();
});
async function getIndexes(collectionName) {
const adapter = Config.get(Parse.applicationId).database.adapter;
const collections = await adapter.database.listCollections({ name: collectionName }).toArray();
if (collections.length === 0) {
return [];
}
return await adapter.database.collection(collectionName).indexes();
}
it('should skip username index when createIndexUserUsername is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserUsername: false },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'username_1')).toBeUndefined();
});
it('should create username index when createIndexUserUsername is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserUsername: true },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'username_1')).toBeDefined();
});
it('should skip case-insensitive username index when createIndexUserUsernameCaseInsensitive is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserUsernameCaseInsensitive: false },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'case_insensitive_username')).toBeUndefined();
});
it('should create case-insensitive username index when createIndexUserUsernameCaseInsensitive is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserUsernameCaseInsensitive: true },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'case_insensitive_username')).toBeDefined();
});
it('should skip email index when createIndexUserEmail is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserEmail: false },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'email_1')).toBeUndefined();
});
it('should create email index when createIndexUserEmail is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserEmail: true },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'email_1')).toBeDefined();
});
it('should skip case-insensitive email index when createIndexUserEmailCaseInsensitive is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserEmailCaseInsensitive: false },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'case_insensitive_email')).toBeUndefined();
});
it('should create case-insensitive email index when createIndexUserEmailCaseInsensitive is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserEmailCaseInsensitive: true },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === 'case_insensitive_email')).toBeDefined();
});
it('should skip email verify token index when createIndexUserEmailVerifyToken is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserEmailVerifyToken: false },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === '_email_verify_token' || idx.name === '_email_verify_token_1')).toBeUndefined();
});
it('should create email verify token index when createIndexUserEmailVerifyToken is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserEmailVerifyToken: true },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === '_email_verify_token' || idx.name === '_email_verify_token_1')).toBeDefined();
});
it('should skip password reset token index when createIndexUserPasswordResetToken is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserPasswordResetToken: false },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === '_perishable_token' || idx.name === '_perishable_token_1')).toBeUndefined();
});
it('should create password reset token index when createIndexUserPasswordResetToken is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexUserPasswordResetToken: true },
});
const indexes = await getIndexes('_User');
expect(indexes.find(idx => idx.name === '_perishable_token' || idx.name === '_perishable_token_1')).toBeDefined();
});
it('should skip role name index when createIndexRoleName is false', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexRoleName: false },
});
const indexes = await getIndexes('_Role');
expect(indexes.find(idx => idx.name === 'name_1')).toBeUndefined();
});
it('should create role name index when createIndexRoleName is true', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: { createIndexRoleName: true },
});
const indexes = await getIndexes('_Role');
expect(indexes.find(idx => idx.name === 'name_1')).toBeDefined();
});
it('should create all indexes by default when options are undefined', async () => {
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
databaseOptions: {},
});
const userIndexes = await getIndexes('_User');
const roleIndexes = await getIndexes('_Role');
// Verify all indexes are created with default behavior (backward compatibility)
expect(userIndexes.find(idx => idx.name === 'username_1')).toBeDefined();
expect(userIndexes.find(idx => idx.name === 'case_insensitive_username')).toBeDefined();
expect(userIndexes.find(idx => idx.name === 'email_1')).toBeDefined();
expect(userIndexes.find(idx => idx.name === 'case_insensitive_email')).toBeDefined();
expect(userIndexes.find(idx => idx.name === '_email_verify_token' || idx.name === '_email_verify_token_1')).toBeDefined();
expect(userIndexes.find(idx => idx.name === '_perishable_token' || idx.name === '_perishable_token_1')).toBeDefined();
expect(roleIndexes.find(idx => idx.name === 'name_1')).toBeDefined();
});
});
describe('logClientEvents', () => {
it('should log MongoDB client events when configured', async () => {
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'warn');
const logClientEvents = [
{
name: 'serverDescriptionChanged',
keys: ['address'],
logLevel: 'warn',
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
// Connect to trigger event listeners setup
await adapter.connect();
// Manually trigger the event to test the listener
const mockEvent = {
address: 'localhost:27017',
previousDescription: { type: 'Unknown' },
newDescription: { type: 'Standalone' },
};
adapter.client.emit('serverDescriptionChanged', mockEvent);
// Verify the log was called with the correct message
expect(logSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event serverDescriptionChanged:.*"address":"localhost:27017"/)
);
await adapter.handleShutdown();
});
it('should log entire event when keys are not specified', async () => {
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'info');
const logClientEvents = [
{
name: 'connectionPoolReady',
logLevel: 'info',
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
await adapter.connect();
const mockEvent = {
address: 'localhost:27017',
options: { maxPoolSize: 100 },
};
adapter.client.emit('connectionPoolReady', mockEvent);
expect(logSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event connectionPoolReady:.*"address":"localhost:27017".*"options"/)
);
await adapter.handleShutdown();
});
it('should extract nested keys using dot notation', async () => {
const logger = require('../lib/logger').logger;
const logSpy = spyOn(logger, 'warn');
const logClientEvents = [
{
name: 'topologyDescriptionChanged',
keys: ['previousDescription.type', 'newDescription.type', 'newDescription.servers.size'],
logLevel: 'warn',
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
await adapter.connect();
const mockEvent = {
topologyId: 1,
previousDescription: { type: 'Unknown' },
newDescription: {
type: 'ReplicaSetWithPrimary',
servers: { size: 3 },
},
};
adapter.client.emit('topologyDescriptionChanged', mockEvent);
expect(logSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event topologyDescriptionChanged:.*"previousDescription.type":"Unknown".*"newDescription.type":"ReplicaSetWithPrimary".*"newDescription.servers.size":3/)
);
await adapter.handleShutdown();
});
it('should handle invalid log level gracefully', async () => {
const logger = require('../lib/logger').logger;
const infoSpy = spyOn(logger, 'info');
const logClientEvents = [
{
name: 'connectionPoolReady',
keys: ['address'],
logLevel: 'invalidLogLevel', // Invalid log level
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
await adapter.connect();
const mockEvent = {
address: 'localhost:27017',
};
adapter.client.emit('connectionPoolReady', mockEvent);
// Should fallback to 'info' level
expect(infoSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event connectionPoolReady:.*"address":"localhost:27017"/)
);
await adapter.handleShutdown();
});
it('should handle Map and Set instances in events', async () => {
const logger = require('../lib/logger').logger;
const warnSpy = spyOn(logger, 'warn');
const logClientEvents = [
{
name: 'customEvent',
logLevel: 'warn',
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
await adapter.connect();
const mockEvent = {
mapData: new Map([['key1', 'value1'], ['key2', 'value2']]),
setData: new Set([1, 2, 3]),
};
adapter.client.emit('customEvent', mockEvent);
// Should serialize Map and Set properly
expect(warnSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event customEvent:.*"mapData":\{"key1":"value1","key2":"value2"\}.*"setData":\[1,2,3\]/)
);
await adapter.handleShutdown();
});
it('should handle missing keys in event object', async () => {
const logger = require('../lib/logger').logger;
const infoSpy = spyOn(logger, 'info');
const logClientEvents = [
{
name: 'testEvent',
keys: ['nonexistent.nested.key', 'another.missing'],
logLevel: 'info',
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
await adapter.connect();
const mockEvent = {
actualField: 'value',
};
adapter.client.emit('testEvent', mockEvent);
// Should handle missing keys gracefully with undefined values
expect(infoSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event testEvent:/)
);
await adapter.handleShutdown();
});
it('should handle circular references gracefully', async () => {
const logger = require('../lib/logger').logger;
const infoSpy = spyOn(logger, 'info');
const logClientEvents = [
{
name: 'circularEvent',
logLevel: 'info',
},
];
const adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { logClientEvents },
});
await adapter.connect();
// Create circular reference
const mockEvent = { name: 'test' };
mockEvent.self = mockEvent;
adapter.client.emit('circularEvent', mockEvent);
// Should handle circular reference with [Circular] marker
expect(infoSpy).toHaveBeenCalledWith(
jasmine.stringMatching(/MongoDB client event circularEvent:.*\[Circular\]/)
);
await adapter.handleShutdown();
});
});
});
+18
View File
@@ -521,6 +521,23 @@ describe('parseObjectToMongoObjectForCreate', () => {
expect(output.authData).toBe('random');
done();
});
it('should only transform authData.provider.id for _User class', () => {
// Test that for _User class, authData.facebook.id is transformed
const userInput = {
'authData.facebook.id': '10000000000000001',
};
const userOutput = transform.transformWhere('_User', userInput, { fields: {} });
expect(userOutput['_auth_data_facebook.id']).toBe('10000000000000001');
// Test that for non-User classes, authData.facebook.id is NOT transformed
const customInput = {
'authData.facebook.id': '10000000000000001',
};
const customOutput = transform.transformWhere('SpamAlerts', customInput, { fields: {} });
expect(customOutput['authData.facebook.id']).toBe('10000000000000001');
expect(customOutput['_auth_data_facebook.id']).toBeUndefined();
});
});
it('cannot have a custom field name beginning with underscore', done => {
@@ -675,4 +692,5 @@ describe('relativeTimeToDate', () => {
});
});
});
});
+133 -43
View File
@@ -1,6 +1,7 @@
'use strict';
const request = require('../lib/request');
const path = require('path');
const fs = require('fs').promises;
const mustache = require('mustache');
const Utils = require('../lib/Utils');
@@ -108,7 +109,7 @@ describe('Pages Router', () => {
const res = await request({
method: 'POST',
url: 'http://localhost:8378/1/apps/test/request_password_reset',
body: `new_password=user1&token=43634643&username=username`,
body: `new_password=user1&token=43634643`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest',
@@ -124,7 +125,7 @@ describe('Pages Router', () => {
await request({
method: 'POST',
url: 'http://localhost:8378/1/apps/test/request_password_reset',
body: `new_password=&token=132414&username=Johnny`,
body: `new_password=&token=132414`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest',
@@ -137,30 +138,12 @@ describe('Pages Router', () => {
}
});
it('request_password_reset: responds with AJAX error on missing username', async () => {
try {
await request({
method: 'POST',
url: 'http://localhost:8378/1/apps/test/request_password_reset',
body: `new_password=user1&token=43634643&username=`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest',
},
followRedirects: false,
});
} catch (error) {
expect(error.status).not.toBe(302);
expect(error.text).toEqual('{"code":200,"error":"Missing username"}');
}
});
it('request_password_reset: responds with AJAX error on missing token', async () => {
try {
await request({
method: 'POST',
url: 'http://localhost:8378/1/apps/test/request_password_reset',
body: `new_password=user1&token=&username=Johnny`,
body: `new_password=user1&token=`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest',
@@ -577,7 +560,7 @@ describe('Pages Router', () => {
spyOnProperty(Page.prototype, 'defaultFile').and.returnValue(jsonPageFile);
const response = await request({
url: `http://localhost:8378/1/apps/test/request_password_reset?token=exampleToken&username=exampleUsername&locale=${exampleLocale}`,
url: `http://localhost:8378/1/apps/test/request_password_reset?token=exampleToken&locale=${exampleLocale}`,
followRedirects: false,
}).catch(e => e);
expect(response.status).toEqual(200);
@@ -626,7 +609,7 @@ describe('Pages Router', () => {
await reconfigureServer(config);
const response = await request({
url:
'http://localhost:8378/1/apps/test/request_password_reset?token=exampleToken&username=exampleUsername&locale=de-AT',
'http://localhost:8378/1/apps/test/request_password_reset?token=exampleToken&locale=de-AT',
followRedirects: false,
method: 'POST',
});
@@ -640,7 +623,7 @@ describe('Pages Router', () => {
await reconfigureServer(config);
const response = await request({
url:
'http://localhost:8378/1/apps/test/request_password_reset?token=exampleToken&username=exampleUsername&locale=de-AT',
'http://localhost:8378/1/apps/test/request_password_reset?token=exampleToken&locale=de-AT',
followRedirects: false,
method: 'GET',
});
@@ -676,13 +659,11 @@ describe('Pages Router', () => {
const appId = linkResponse.headers['x-parse-page-param-appid'];
const token = linkResponse.headers['x-parse-page-param-token'];
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'];
const passwordResetPagePath = pageResponse.calls.all()[0].args[0];
expect(appId).toBeDefined();
expect(token).toBeDefined();
expect(locale).toBeDefined();
expect(username).toBeDefined();
expect(publicServerUrl).toBeDefined();
expect(passwordResetPagePath).toMatch(
new RegExp(`\/${exampleLocale}\/${pages.passwordReset.defaultFile}`)
@@ -696,7 +677,6 @@ describe('Pages Router', () => {
body: {
token,
locale,
username,
new_password: 'newPassword',
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
@@ -738,7 +718,7 @@ describe('Pages Router', () => {
);
});
it('localizes end-to-end for verify email: success', async () => {
it_id('2845c2ea-23ba-45d2-a33f-63181d419bca')(it)('localizes end-to-end for verify email: success', async () => {
await reconfigureServer(config);
const sendVerificationEmail = spyOn(
config.emailAdapter,
@@ -749,6 +729,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);
@@ -766,7 +747,7 @@ describe('Pages Router', () => {
);
});
it('localizes end-to-end for verify email: invalid verification link - link send success', async () => {
it_id('f2272b94-b4ac-474f-8e47-1ca74de136f5')(it)('localizes end-to-end for verify email: invalid verification link - link send success', async () => {
await reconfigureServer(config);
const sendVerificationEmail = spyOn(
config.emailAdapter,
@@ -777,6 +758,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);
@@ -791,15 +773,13 @@ describe('Pages Router', () => {
const appId = linkResponse.headers['x-parse-page-param-appid'];
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'];
const invalidVerificationPagePath = pageResponse.calls.all()[0].args[0];
expect(appId).toBeDefined();
expect(locale).toBe(exampleLocale);
expect(username).toBeDefined();
expect(publicServerUrl).toBeDefined();
expect(invalidVerificationPagePath).toMatch(
new RegExp(`\/${exampleLocale}\/${pages.emailVerificationLinkExpired.defaultFile}`)
new RegExp(`\/${exampleLocale}\/${pages.emailVerificationLinkInvalid.defaultFile}`)
);
const formUrl = `${publicServerUrl}/apps/${appId}/resend_verification_email`;
@@ -808,7 +788,7 @@ describe('Pages Router', () => {
method: 'POST',
body: {
locale,
username,
username: 'exampleUsername',
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
followRedirects: false,
@@ -819,7 +799,7 @@ describe('Pages Router', () => {
);
});
it('localizes end-to-end for verify email: invalid verification link - link send fail', async () => {
it_id('1d46d36a-e455-4ae7-8717-e0d286e95f02')(it)('localizes end-to-end for verify email: invalid verification link - link send fail', async () => {
await reconfigureServer(config);
const sendVerificationEmail = spyOn(
config.emailAdapter,
@@ -830,6 +810,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);
@@ -844,15 +825,15 @@ describe('Pages Router', () => {
const appId = linkResponse.headers['x-parse-page-param-appid'];
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);
expect(username).toBeDefined();
expect(publicServerUrl).toBeDefined();
expect(invalidVerificationPagePath).toMatch(
new RegExp(`\/${exampleLocale}\/${pages.emailVerificationLinkExpired.defaultFile}`)
new RegExp(`\/${exampleLocale}\/${pages.emailVerificationLinkInvalid.defaultFile}`)
);
spyOn(UserController.prototype, 'resendVerificationEmail').and.callFake(() =>
@@ -865,7 +846,7 @@ describe('Pages Router', () => {
method: 'POST',
body: {
locale,
username,
username: 'exampleUsername',
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
followRedirects: false,
@@ -977,6 +958,50 @@ describe('Pages Router', () => {
expect(response.status).toBe(404);
expect(response.text).toBe('Not found.');
});
it('rejects requesting file from sibling directory with prefix-colliding name via encoded path traversal', async () => {
// Create a temporary pages directory and a sibling directory whose name
// starts with the same prefix (e.g. "pages" vs "pages-secret"), which
// would bypass a naive `startsWith` check without a path separator.
const baseDir = path.join(__dirname, 'tmp-pages-exploit-test');
const pagesDir = path.join(baseDir, 'pages');
const siblingDir = path.join(baseDir, 'pages-secret');
const marker = `SECRET_CONTENT_${Date.now()}`;
try {
await fs.mkdir(pagesDir, { recursive: true });
await fs.mkdir(siblingDir, { recursive: true });
// Copy a required HTML file so the pages router initializes correctly
const publicDir = path.resolve(__dirname, '../public');
const htmlFile = await fs.readFile(
path.join(publicDir, 'email_verification_link_invalid.html'),
'utf-8'
);
await fs.writeFile(
path.join(pagesDir, 'email_verification_link_invalid.html'),
htmlFile
);
// Write a secret file in the sibling directory
await fs.writeFile(path.join(siblingDir, 'secret.txt'), marker);
config.pages.pagesPath = pagesDir;
await reconfigureServer(config);
// Use URL-encoded path traversal: %2e%2e%2f = ../
// This reaches the sibling "pages-secret" directory which shares
// the "pages" prefix with the configured pagesPath directory name.
const url = `${config.publicServerURL}/apps/%2e%2e%2fpages-secret%2fsecret.txt`;
const response = await request({
url: url,
followRedirects: false,
}).catch(e => e);
expect(response.status).toBe(404);
expect(response.text).not.toContain(marker);
} finally {
await fs.rm(baseDir, { recursive: true, force: true });
}
});
});
describe('custom route', () => {
@@ -1150,12 +1175,10 @@ describe('Pages Router', () => {
const appId = linkResponse.headers['x-parse-page-param-appid'];
const token = linkResponse.headers['x-parse-page-param-token'];
const username = linkResponse.headers['x-parse-page-param-username'];
const publicServerUrl = linkResponse.headers['x-parse-page-param-publicserverurl'];
const passwordResetPagePath = pageResponse.calls.all()[0].args[0];
expect(appId).toBeDefined();
expect(token).toBeDefined();
expect(username).toBeDefined();
expect(publicServerUrl).toBeDefined();
expect(passwordResetPagePath).toMatch(new RegExp(`\/${pages.passwordReset.defaultFile}`));
pageResponse.calls.reset();
@@ -1166,7 +1189,6 @@ describe('Pages Router', () => {
method: 'POST',
body: {
token,
username,
new_password: 'newPassword',
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
@@ -1178,7 +1200,7 @@ describe('Pages Router', () => {
);
});
it('email verification works with custom endpoint', async () => {
it_id('81c1c28e-5dfd-4ffb-a09b-283156c08483')(it)('email verification works with custom endpoint', async () => {
config.pages.pagesEndpoint = 'customEndpoint';
await reconfigureServer(config);
const sendVerificationEmail = spyOn(
@@ -1190,6 +1212,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,10 +1220,77 @@ 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}`));
});
});
});
describe('XSS Protection', () => {
beforeEach(async () => {
await reconfigureServer({
appId: 'test',
appName: 'exampleAppname',
publicServerURL: 'http://localhost:8378/1',
pages: { enableRouter: true },
});
});
it('should escape XSS payloads in token parameter', async () => {
const xssPayload = '"><script>alert("XSS")</script>';
const response = await request({
url: `http://localhost:8378/1/apps/choose_password?token=${encodeURIComponent(xssPayload)}&username=test&appId=test`,
});
expect(response.status).toBe(200);
expect(response.text).not.toContain('<script>alert("XSS")</script>');
expect(response.text).toContain('&quot;&gt;&lt;script&gt;');
});
it('should escape XSS in username parameter', async () => {
const xssUsername = '<img src=x onerror=alert(1)>';
const response = await request({
url: `http://localhost:8378/1/apps/choose_password?username=${encodeURIComponent(xssUsername)}&appId=test`,
});
expect(response.status).toBe(200);
expect(response.text).not.toContain('<img src=x onerror=alert(1)>');
expect(response.text).toContain('&lt;img');
});
it('should escape XSS in locale parameter', async () => {
const xssLocale = '"><svg/onload=alert(1)>';
const response = await request({
url: `http://localhost:8378/1/apps/choose_password?locale=${encodeURIComponent(xssLocale)}&appId=test`,
});
expect(response.status).toBe(200);
expect(response.text).not.toContain('<svg/onload=alert(1)>');
expect(response.text).toContain('&quot;&gt;&lt;svg');
});
it('should handle legitimate usernames with quotes correctly', async () => {
const username = "O'Brien";
const response = await request({
url: `http://localhost:8378/1/apps/choose_password?username=${encodeURIComponent(username)}&appId=test`,
});
expect(response.status).toBe(200);
// Should be properly escaped as HTML entity
expect(response.text).toContain('O&#39;Brien');
// Should NOT contain unescaped quote that breaks HTML
expect(response.text).not.toContain('value="O\'Brien"');
});
it('should handle legitimate usernames with ampersands correctly', async () => {
const username = 'Smith & Co';
const response = await request({
url: `http://localhost:8378/1/apps/choose_password?username=${encodeURIComponent(username)}&appId=test`,
});
expect(response.status).toBe(200);
// Should be properly escaped
expect(response.text).toContain('Smith &amp; Co');
});
});
});
+5 -7
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 });
}
};
@@ -113,7 +111,7 @@ const setup = function () {
};
describe('Parse.Push', () => {
it('should properly send push', async () => {
it_id('d1e591c4-2b21-466b-9ee2-5be467b6b771')(it)('should properly send push', async () => {
const { sendToInstallationSpy } = await setup();
const pushStatusId = await Parse.Push.send({
where: {
@@ -128,7 +126,7 @@ describe('Parse.Push', () => {
expect(sendToInstallationSpy.calls.count()).toEqual(10);
});
it('should properly send push with lowercaseIncrement', async () => {
it_id('2a58e3c7-b6f3-4261-a384-6c893b2ac3f3')(it)('should properly send push with lowercaseIncrement', async () => {
await setup();
const pushStatusId = await Parse.Push.send({
where: {
@@ -142,7 +140,7 @@ describe('Parse.Push', () => {
await pushCompleted(pushStatusId);
});
it('should not allow clients to query _PushStatus', async () => {
it_id('e21780b6-2cdd-467e-8013-81030f3288e9')(it)('should not allow clients to query _PushStatus', async () => {
await setup();
const pushStatusId = await Parse.Push.send({
where: {
@@ -168,7 +166,7 @@ describe('Parse.Push', () => {
}
});
it('should allow master key to query _PushStatus', async () => {
it_id('924cf5f5-f684-4925-978a-e52c0c457366')(it)('should allow master key to query _PushStatus', async () => {
await setup();
const pushStatusId = await Parse.Push.send({
where: {
+30 -10
View File
@@ -5,17 +5,9 @@ const Config = require('../lib/Config');
const auth = require('../lib/Auth');
describe('Parse.ACL', () => {
it('acl must be valid', done => {
it('acl must be valid', () => {
const user = new Parse.User();
ok(
!user.setACL("Ceci n'est pas un ACL.", {
error: function (user, error) {
equal(error.code, -1);
done();
},
}),
'setACL should have returned false.'
);
expect(() => user.setACL('ACL')).toThrow(new Parse.Error(Parse.Error.OTHER_CAUSE, 'ACL must be a Parse ACL.'));
});
it('refresh object with acl', async done => {
@@ -931,4 +923,32 @@ describe('Parse.ACL', () => {
rest.create(config, auth.nobody(config), '_User', anonUser);
});
it('support defaultACL in schema', async () => {
await new Parse.Object('TestObject').save();
const schema = await Parse.Server.database.loadSchema();
await schema.updateClass(
'TestObject',
{},
{
create: {
'*': true,
},
ACL: {
'*': { read: true },
currentUser: { read: true, write: true },
},
}
);
const acls = new Parse.ACL();
acls.setPublicReadAccess(true);
const user = await Parse.User.signUp('testuser', 'p@ssword');
const obj = new Parse.Object('TestObject');
await obj.save(null, { sessionToken: user.getSessionToken() });
expect(obj.getACL()).toBeDefined();
const acl = obj.getACL().toJSON();
expect(acl['*']).toEqual({ read: true });
expect(acl[user.id].write).toBeTrue();
expect(acl[user.id].read).toBeTrue();
});
});
+19 -14
View File
@@ -6,7 +6,7 @@ const request = require('../lib/request');
const Parse = require('parse/node');
const Config = require('../lib/Config');
const SchemaController = require('../lib/Controllers/SchemaController');
const TestUtils = require('../lib/TestUtils');
const { destroyAllDataPermanently } = require('../lib/TestUtils');
const userSchema = SchemaController.convertSchemaToAdapterSchema({
className: '_User',
@@ -33,9 +33,7 @@ describe('miscellaneous', () => {
expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar');
});
});
describe('miscellaneous', function () {
it('create a GameScore object', function (done) {
const obj = new Parse.Object('GameScore');
obj.set('score', 1337);
@@ -163,7 +161,7 @@ describe('miscellaneous', function () {
expect(numCreated).toBe(1);
});
it('ensure that if people already have duplicate users, they can still sign up new users', async done => {
it_id('be1b9ac7-5e5f-4e91-b044-2bd8fb7622ad')(it)('ensure that if people already have duplicate users, they can still sign up new users', async done => {
try {
await Parse.User.logOut();
} catch (e) {
@@ -171,7 +169,7 @@ describe('miscellaneous', function () {
}
const config = Config.get('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
destroyAllDataPermanently()
.then(() => config.database.adapter.performInitialization({ VolatileClassesSchemas: [] }))
.then(() => config.database.adapter.createClass('_User', userSchema))
.then(() =>
@@ -209,10 +207,10 @@ describe('miscellaneous', function () {
});
});
it('ensure that if people already have duplicate emails, they can still sign up new users', done => {
it_id('d00f907e-41b9-40f6-8168-63e832199a8c')(it)('ensure that if people already have duplicate emails, they can still sign up new users', done => {
const config = Config.get('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
destroyAllDataPermanently()
.then(() => config.database.adapter.performInitialization({ VolatileClassesSchemas: [] }))
.then(() => config.database.adapter.createClass('_User', userSchema))
.then(() =>
@@ -289,7 +287,7 @@ describe('miscellaneous', function () {
}, fail);
});
it('increment with a user object', function (done) {
it_id('33db6efe-7c02-496c-8595-0ef627a94103')(it)('increment with a user object', function (done) {
createTestUser()
.then(user => {
user.increment('foo');
@@ -317,7 +315,7 @@ describe('miscellaneous', function () {
);
});
it('save various data types', function (done) {
it_id('bef99522-bcfd-4f79-ba9e-3c3845550401')(it)('save various data types', function (done) {
const obj = new TestObject();
obj.set('date', new Date());
obj.set('array', [1, 2, 3]);
@@ -951,7 +949,7 @@ describe('miscellaneous', function () {
);
});
it('return the updated fields on PUT', async () => {
it_id('e9e718a9-4465-4158-b13e-f146855a8892')(it)('return the updated fields on PUT', async () => {
const obj = new Parse.Object('GameScore');
const pointer = new Parse.Object('Child');
await pointer.save();
@@ -1023,7 +1021,7 @@ describe('miscellaneous', function () {
expect(body.updatedAt).not.toBeUndefined();
});
it('should response should not change with triggers', async () => {
it_id('ea358b59-03c0-45c9-abc7-1fdd67573029')(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 => {
@@ -1268,6 +1266,7 @@ 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;
});
@@ -1285,6 +1284,7 @@ describe('miscellaneous', function () {
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);
@@ -1489,7 +1489,7 @@ describe('miscellaneous', function () {
});
});
it('properly returns incremented values (#1554)', done => {
it_id('b2cd9cf2-13fa-4acd-aaa9-6f81fc1858db')(it)('properly returns incremented values (#1554)', done => {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
@@ -1678,7 +1678,7 @@ describe('miscellaneous', function () {
});
});
it('purge all objects in class', done => {
it_id('8f99ee20-3da7-45ec-b867-ea0eb87524a9')(it)('purge all objects in class', done => {
const object = new Parse.Object('TestObject');
object.set('foo', 'bar');
const object2 = new Parse.Object('TestObject');
@@ -1710,11 +1710,15 @@ describe('miscellaneous', function () {
});
it('fail on purge all objects in class without master key', done => {
const logger = require('../lib/logger').default;
const loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
loggerErrorSpy.calls.reset();
request({
method: 'DELETE',
headers: headers,
@@ -1724,7 +1728,8 @@ describe('miscellaneous', function () {
fail('Should not succeed');
})
.catch(response => {
expect(response.data.error).toEqual('unauthorized: master key is required');
expect(response.data.error).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
});
});
+144
View File
@@ -0,0 +1,144 @@
const Config = require('../lib/Config');
describe('Config Keys', () => {
const invalidKeyErrorMessage = 'Invalid key\\(s\\) found in Parse Server configuration';
let loggerErrorSpy;
beforeEach(async () => {
const logger = require('../lib/logger').logger;
loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
spyOn(Config, 'validateOptions').and.callFake(() => {});
});
it('recognizes invalid keys in root', async () => {
await expectAsync(reconfigureServer({
invalidKey: 1,
})).toBeResolved();
const error = loggerErrorSpy.calls.all().reduce((s, call) => s += call.args[0], '');
expect(error).toMatch(invalidKeyErrorMessage);
});
it('recognizes invalid keys in pages.customUrls', async () => {
await expectAsync(reconfigureServer({
pages: {
customUrls: {
invalidKey: 1,
EmailVerificationSendFail: 1,
}
}
})).toBeResolved();
const error = loggerErrorSpy.calls.all().reduce((s, call) => s += call.args[0], '');
expect(error).toMatch(invalidKeyErrorMessage);
expect(error).toMatch(`invalidKey`);
expect(error).toMatch(`EmailVerificationSendFail`);
});
it('recognizes invalid keys in liveQueryServerOptions', async () => {
await expectAsync(reconfigureServer({
liveQueryServerOptions: {
invalidKey: 1,
MasterKey: 1,
}
})).toBeResolved();
const error = loggerErrorSpy.calls.all().reduce((s, call) => s += call.args[0], '');
expect(error).toMatch(invalidKeyErrorMessage);
expect(error).toMatch(`MasterKey`);
});
it('recognizes invalid keys in rateLimit', async () => {
await expectAsync(reconfigureServer({
rateLimit: [
{ invalidKey: 1 },
{ RequestPath: 1 },
{ RequestTimeWindow: 1 },
]
})).toBeRejected();
const error = loggerErrorSpy.calls.all().reduce((s, call) => s += call.args[0], '');
expect(error).toMatch(invalidKeyErrorMessage);
expect(error).toMatch('rateLimit\\[0\\]\\.invalidKey');
expect(error).toMatch('rateLimit\\[1\\]\\.RequestPath');
expect(error).toMatch('rateLimit\\[2\\]\\.RequestTimeWindow');
});
it_only_db('mongo')('recognizes valid keys in default configuration', async () => {
await expectAsync(reconfigureServer({
...defaultConfiguration,
})).toBeResolved();
expect(loggerErrorSpy.calls.all().reduce((s, call) => s += call.args[0], '')).not.toMatch(invalidKeyErrorMessage);
});
it_only_db('mongo')('recognizes valid keys in databaseOptions (MongoDB)', async () => {
await expectAsync(reconfigureServer({
databaseURI: 'mongodb://localhost:27017/parse',
filesAdapter: null,
databaseAdapter: null,
databaseOptions: {
appName: 'MyParseApp',
// Cannot be tested as it requires authentication setup
// authMechanism: 'SCRAM-SHA-256',
// authMechanismProperties: { SERVICE_NAME: 'mongodb' },
authSource: 'admin',
autoSelectFamily: true,
autoSelectFamilyAttemptTimeout: 3000,
compressors: ['zlib'],
connectTimeoutMS: 5000,
directConnection: false,
disableIndexFieldValidation: true,
forceServerObjectId: false,
heartbeatFrequencyMS: 10000,
localThresholdMS: 15,
maxConnecting: 2,
maxIdleTimeMS: 60000,
maxPoolSize: 10,
maxStalenessSeconds: 90,
maxTimeMS: 1000,
minPoolSize: 5,
// Cannot be tested as it requires a proxy setup
// proxyHost: 'proxy.example.com',
// proxyPassword: 'proxypass',
// proxyPort: 1080,
// proxyUsername: 'proxyuser',
readConcernLevel: 'majority',
readPreference: 'secondaryPreferred',
readPreferenceTags: [{ dc: 'east' }],
// Cannot be tested as it requires a replica set setup
// replicaSet: 'myReplicaSet',
retryReads: true,
retryWrites: true,
serverMonitoringMode: 'auto',
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 5000,
// Cannot be tested as it requires a replica cluster setup
// srvMaxHosts: 0,
// srvServiceName: 'mongodb',
ssl: false,
tls: false,
tlsAllowInvalidCertificates: false,
tlsAllowInvalidHostnames: false,
tlsCAFile: __dirname + '/support/cert/cert.pem',
tlsCertificateKeyFile: __dirname + '/support/cert/cert.pem',
tlsCertificateKeyFilePassword: 'password',
waitQueueTimeoutMS: 5000,
zlibCompressionLevel: 6,
},
})).toBeResolved();
await expectAsync(reconfigureServer({
databaseURI: 'mongodb://localhost:27017/parse',
filesAdapter: null,
databaseAdapter: null,
databaseOptions: {
// The following option needs to be tested separately due to driver config rules
tlsInsecure: false,
},
})).toBeResolved();
expect(loggerErrorSpy.calls.all().reduce((s, call) => s += call.args[0], '')).not.toMatch(invalidKeyErrorMessage);
});
});
+176 -50
View File
@@ -13,6 +13,13 @@ for (let i = 0; i < str.length; i++) {
}
describe('Parse.File testing', () => {
let loggerErrorSpy;
beforeEach(() => {
const logger = require('../lib/logger').default;
loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
});
describe('creating files', () => {
it('works with Content-Type', done => {
const headers = {
@@ -146,6 +153,7 @@ describe('Parse.File testing', () => {
const b = response.data;
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*thefile.jpg$/);
// missing X-Parse-Master-Key header
loggerErrorSpy.calls.reset();
request({
method: 'DELETE',
headers: {
@@ -156,8 +164,10 @@ describe('Parse.File testing', () => {
}).then(fail, response => {
const del_b = response.data;
expect(response.status).toEqual(403);
expect(del_b.error).toMatch(/unauthorized/);
expect(del_b.error).toBe('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
// incorrect X-Parse-Master-Key header
loggerErrorSpy.calls.reset();
request({
method: 'DELETE',
headers: {
@@ -169,7 +179,8 @@ describe('Parse.File testing', () => {
}).then(fail, response => {
const del_b2 = response.data;
expect(response.status).toEqual(403);
expect(del_b2.error).toMatch(/unauthorized/);
expect(del_b2.error).toBe('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
});
});
@@ -378,6 +389,26 @@ describe('Parse.File testing', () => {
expect(response.headers['content-type']).toMatch(/^text\/html/);
});
it('works without Content-Type and extension', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const result = await request({
method: 'POST',
headers: headers,
url: 'http://localhost:8378/1/files/file',
body: '<html></html>\n',
});
expect(result.data.url.includes('file.txt')).toBeTrue();
expect(result.data.name.includes('file.txt')).toBeTrue();
});
it('filename is url encoded', done => {
const headers = {
'Content-Type': 'text/html',
@@ -633,6 +664,80 @@ describe('Parse.File testing', () => {
done();
});
});
describe('URI-backed file upload is disabled to prevent SSRF attack', () => {
const express = require('express');
let testServer;
let testServerPort;
let requestsMade;
beforeEach(async () => {
requestsMade = [];
const app = express();
app.use((req, res) => {
requestsMade.push({ url: req.url, method: req.method });
res.status(200).send('test file content');
});
testServer = app.listen(0);
testServerPort = testServer.address().port;
});
afterEach(async () => {
if (testServer) {
await new Promise(resolve => testServer.close(resolve));
}
Parse.Cloud._removeAllHooks();
});
it('does not access URI when file upload attempted over REST', async () => {
const response = await request({
method: 'POST',
url: 'http://localhost:8378/1/classes/TestClass',
headers: {
'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
body: {
file: {
__type: 'File',
name: 'test.txt',
_source: {
format: 'uri',
uri: `http://127.0.0.1:${testServerPort}/secret-file.txt`,
},
},
},
});
expect(response.status).toBe(201);
// Verify no HTTP request was made to the URI
expect(requestsMade.length).toBe(0);
});
it('does not access URI when file created in beforeSave trigger', async () => {
Parse.Cloud.beforeSave(Parse.File, () => {
return new Parse.File('trigger-file.txt', {
uri: `http://127.0.0.1:${testServerPort}/secret-file.txt`,
});
});
await expectAsync(
request({
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
url: 'http://localhost:8378/1/files/test.txt',
body: 'test content',
})
).toBeRejectedWith(jasmine.objectContaining({
status: 400
}));
// Verify no HTTP request was made to the URI
expect(requestsMade.length).toBe(0);
});
});
});
describe('deleting files', () => {
@@ -789,59 +894,11 @@ describe('Parse.File testing', () => {
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',
@@ -1364,6 +1421,75 @@ describe('Parse.File testing', () => {
);
});
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('default should block SVG files', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
},
});
const headers = {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
};
const svgContent = Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>').toString('base64');
for (const extension of ['svg', 'SVG', 'Svg']) {
await expectAsync(
request({
method: 'POST',
headers: headers,
url: `http://localhost:8378/1/files/malicious.${extension}`,
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'image/svg+xml',
base64: svgContent,
}),
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension ${extension} is disabled.`)
);
}
});
it('default should block SVG content type without file extension', async () => {
await reconfigureServer({
fileUpload: {
enableForPublic: true,
},
});
const svgContent = Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>').toString('base64');
await expectAsync(
request({
method: 'POST',
url: 'http://localhost:8378/1/files/file',
body: JSON.stringify({
_ApplicationId: 'test',
_JavaScriptKey: 'test',
_ContentType: 'image/svg+xml',
base64: svgContent,
}),
}).catch(e => {
throw new Error(e.data.error);
})
).toBeRejectedWith(
new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension svg+xml is disabled.`)
);
});
it('works with a period in the file name', async () => {
await reconfigureServer({
fileUpload: {
+11 -11
View File
@@ -93,7 +93,7 @@ describe('Parse.GeoPoint testing', () => {
);
});
it('geo line', async done => {
it_id('bbd9e2f6-7f61-458f-98f2-4a563586cd8d')(it)('geo line', async done => {
const line = [];
for (let i = 0; i < 10; ++i) {
const obj = new TestObject();
@@ -143,7 +143,7 @@ describe('Parse.GeoPoint testing', () => {
);
});
it('geo max distance medium', async () => {
it_id('e1e86b38-b8a4-4109-8330-a324fe628e0c')(it)('geo max distance medium', async () => {
const objects = [];
[0, 1, 2].map(function (i) {
const obj = new TestObject();
@@ -207,7 +207,7 @@ describe('Parse.GeoPoint testing', () => {
done();
});
it('geo max distance in km california', async () => {
it_id('05f1a454-56b1-4f2e-908e-408a9222cbae')(it)('geo max distance in km california', async () => {
await makeSomeGeoPoints();
const sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
const query = new Parse.Query(TestObject);
@@ -246,7 +246,7 @@ describe('Parse.GeoPoint testing', () => {
equal(results.length, 3);
});
it('geo max distance in miles california', async () => {
it_id('9ee376ad-dd6c-4c17-ad28-c7899a4411f1')(it)('geo max distance in miles california', async () => {
await makeSomeGeoPoints();
const sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
const query = new Parse.Query(TestObject);
@@ -276,7 +276,7 @@ describe('Parse.GeoPoint testing', () => {
equal(results.length, 0);
});
it('returns nearest location', async () => {
it_id('9e35a89e-bc2c-4ec5-b25a-8d1890a55233')(it)('returns nearest location', async () => {
await makeSomeGeoPoints();
const sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
const query = new Parse.Query(TestObject);
@@ -286,7 +286,7 @@ describe('Parse.GeoPoint testing', () => {
equal(results[1].get('name'), 'Sacramento');
});
it('works with geobox queries', done => {
it_id('6df434b0-142d-4302-bbc6-a6ec5a9d9c68')(it)('works with geobox queries', done => {
const inbound = new Parse.GeoPoint(1.5, 1.5);
const onbound = new Parse.GeoPoint(10, 10);
const outbound = new Parse.GeoPoint(20, 20);
@@ -356,7 +356,7 @@ describe('Parse.GeoPoint testing', () => {
});
});
it('supports withinPolygon open path', done => {
it_id('d9fbc5c6-f767-47d6-bb44-3858eb9df15a')(it)('supports withinPolygon open path', done => {
const inbound = new Parse.GeoPoint(1.5, 1.5);
const onbound = new Parse.GeoPoint(10, 10);
const outbound = new Parse.GeoPoint(20, 20);
@@ -394,7 +394,7 @@ describe('Parse.GeoPoint testing', () => {
}, done.fail);
});
it('supports withinPolygon closed path', done => {
it_id('3ec537bd-839a-4c93-a48b-b4a249820074')(it)('supports withinPolygon closed path', done => {
const inbound = new Parse.GeoPoint(1.5, 1.5);
const onbound = new Parse.GeoPoint(10, 10);
const outbound = new Parse.GeoPoint(20, 20);
@@ -433,7 +433,7 @@ describe('Parse.GeoPoint testing', () => {
}, done.fail);
});
it('supports withinPolygon Polygon object', done => {
it_id('0a248e11-3598-480a-9ab5-8a0b259258e4')(it)('supports withinPolygon Polygon object', done => {
const inbound = new Parse.GeoPoint(1.5, 1.5);
const onbound = new Parse.GeoPoint(10, 10);
const outbound = new Parse.GeoPoint(20, 20);
@@ -752,7 +752,7 @@ describe('Parse.GeoPoint testing', () => {
equal(count, 1);
});
it('withinKilometers complex supports count', async () => {
it_id('0b073d31-0d41-41e7-bd60-f636ffb759dc')(it)('withinKilometers complex supports count', async () => {
const inside = new Parse.GeoPoint(10, 10);
const middle = new Parse.GeoPoint(20, 20);
const outside = new Parse.GeoPoint(30, 30);
@@ -770,7 +770,7 @@ describe('Parse.GeoPoint testing', () => {
equal(count, 2);
});
it('fails to fetch geopoints that are specifically not at (0,0)', async () => {
it_id('26c9a13d-3d71-452e-a91c-9a4589be021c')(it)('fails to fetch geopoints that are specifically not at (0,0)', async () => {
const tmp = new TestObject({
location: new Parse.GeoPoint({ latitude: 0, longitude: 0 }),
});
+40 -10
View File
@@ -4,7 +4,7 @@ const request = require('../lib/request');
const Config = require('../lib/Config');
describe('a GlobalConfig', () => {
beforeEach(done => {
beforeEach(async () => {
const config = Config.get('test');
const query = on_db(
'mongo',
@@ -16,7 +16,7 @@ describe('a GlobalConfig', () => {
return { objectId: '1' };
}
);
config.database.adapter
await config.database.adapter
.upsertOneObject(
'_GlobalConfig',
{
@@ -28,14 +28,10 @@ describe('a GlobalConfig', () => {
},
query,
{
params: { companies: ['US', 'DK'], internalParam: 'internal' },
params: { companies: ['US', 'DK'], counter: 20, internalParam: 'internal' },
masterKeyOnly: { internalParam: true },
}
)
.then(done, err => {
jfail(err);
done();
});
);
});
const headers = {
@@ -114,6 +110,34 @@ describe('a GlobalConfig', () => {
});
});
it_only_db('mongo')('can addUnique', async () => {
await Parse.Config.save({ companies: { __op: 'AddUnique', objects: ['PA', 'RS', 'E'] } });
const config = await Parse.Config.get();
const companies = config.get('companies');
expect(companies).toEqual(['US', 'DK', 'PA', 'RS', 'E']);
});
it_only_db('mongo')('can add to array', async () => {
await Parse.Config.save({ companies: { __op: 'Add', objects: ['PA'] } });
const config = await Parse.Config.get();
const companies = config.get('companies');
expect(companies).toEqual(['US', 'DK', 'PA']);
});
it_only_db('mongo')('can remove from array', async () => {
await Parse.Config.save({ companies: { __op: 'Remove', objects: ['US'] } });
const config = await Parse.Config.get();
const companies = config.get('companies');
expect(companies).toEqual(['DK']);
});
it('can increment', async () => {
await Parse.Config.save({ counter: { __op: 'Increment', amount: 49 } });
const config = await Parse.Config.get();
const counter = config.get('counter');
expect(counter).toEqual(69);
});
it('can add and retrive files', done => {
request({
method: 'PUT',
@@ -157,7 +181,7 @@ describe('a GlobalConfig', () => {
});
});
it('properly handles delete op', done => {
it_id('5ebbd0cf-d1a5-49d9-aac7-5216abc5cb62')(it)('properly handles delete op', done => {
request({
method: 'PUT',
url: 'http://localhost:8378/1/config',
@@ -165,6 +189,7 @@ describe('a GlobalConfig', () => {
body: {
params: {
companies: { __op: 'Delete' },
counter: { __op: 'Delete' },
internalParam: { __op: 'Delete' },
foo: 'bar',
},
@@ -183,6 +208,7 @@ describe('a GlobalConfig', () => {
try {
expect(response.status).toEqual(200);
expect(body.params.companies).toBeUndefined();
expect(body.params.counter).toBeUndefined();
expect(body.params.foo).toBe('bar');
expect(Object.keys(body.params).length).toBe(1);
} catch (e) {
@@ -194,6 +220,9 @@ describe('a GlobalConfig', () => {
});
it('fail to update if master key is missing', done => {
const logger = require('../lib/logger').default;
const loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
loggerErrorSpy.calls.reset();
request({
method: 'PUT',
url: 'http://localhost:8378/1/config',
@@ -207,7 +236,8 @@ describe('a GlobalConfig', () => {
}).then(fail, response => {
const body = response.data;
expect(response.status).toEqual(403);
expect(body.error).toEqual('unauthorized: master key is required');
expect(body.error).toEqual('Permission denied');
expect(loggerErrorSpy).toHaveBeenCalledWith('Sanitized error:', jasmine.stringContaining('unauthorized: master key is required'));
done();
});
});
+2 -2
View File
@@ -500,7 +500,7 @@ describe('ParseGraphQLSchema', () => {
});
});
describe('alias', () => {
it('Should be able to define alias for get and find query', async () => {
it_id('45282d26-f4c7-4d2d-a7b6-cd8741d5322f')(it)('Should be able to define alias for get and find query', async () => {
const parseGraphQLSchema = new ParseGraphQLSchema({
databaseController,
parseGraphQLController,
@@ -535,7 +535,7 @@ describe('ParseGraphQLSchema', () => {
expect(Object.keys(queries1)).toContain('precious_data');
});
it('Should be able to define alias for mutation', async () => {
it_id('f04b46e3-a25d-401d-a315-3298cfee1df8')(it)('Should be able to define alias for mutation', async () => {
const parseGraphQLSchema = new ParseGraphQLSchema({
databaseController,
parseGraphQLController,
File diff suppressed because it is too large Load Diff

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