build: Release beta (#8525)
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
check-definitions:
|
||||
name: Check Definitions
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.NODE_VERSION }}
|
||||
|
||||
4
.github/workflows/release-automated.yml
vendored
4
.github/workflows/release-automated.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
env:
|
||||
REGISTRY: docker.io
|
||||
IMAGE_NAME: parseplatform/parse-server
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
docs:
|
||||
needs: release
|
||||
if: needs.release.outputs.current_tag != '' && github.ref == 'refs/heads/release'
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
2
.github/workflows/release-manual-docker.yml
vendored
2
.github/workflows/release-manual-docker.yml
vendored
@@ -14,7 +14,7 @@ env:
|
||||
IMAGE_NAME: parseplatform/parse-server
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
@@ -1,3 +1,66 @@
|
||||
# [6.1.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.7...6.1.0-alpha.8) (2023-05-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Allow multiple origins for header `Access-Control-Allow-Origin` ([#8517](https://github.com/parse-community/parse-server/issues/8517)) ([4f15539](https://github.com/parse-community/parse-server/commit/4f15539ac244aa2d393ac5177f7604b43f69e271))
|
||||
|
||||
# [6.1.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.6...6.1.0-alpha.7) (2023-03-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Rate limiting across multiple servers via Redis not working ([#8469](https://github.com/parse-community/parse-server/issues/8469)) ([d9e347d](https://github.com/parse-community/parse-server/commit/d9e347d7413f30f58ffbb8397fc8b5ae23be6ff0))
|
||||
|
||||
# [6.1.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.5...6.1.0-alpha.6) (2023-03-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add rate limiting across multiple servers via Redis ([#8394](https://github.com/parse-community/parse-server/issues/8394)) ([34833e4](https://github.com/parse-community/parse-server/commit/34833e42eec08b812b733be78df0535ab0e096b6))
|
||||
|
||||
# [6.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.4...6.1.0-alpha.5) (2023-03-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
|
||||
|
||||
# [6.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.3...6.1.0-alpha.4) (2023-03-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
|
||||
|
||||
# [6.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.2...6.1.0-alpha.3) (2023-03-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
|
||||
|
||||
# [6.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.1...6.1.0-alpha.2) (2023-03-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Nested date is incorrectly decoded as empty object `{}` when fetching a Parse Object ([#8446](https://github.com/parse-community/parse-server/issues/8446)) ([22d2446](https://github.com/parse-community/parse-server/commit/22d2446dfea2bc339affc20535d181097e152acf))
|
||||
|
||||
# [6.1.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.0.0...6.1.0-alpha.1) (2023-03-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Security upgrade jsonwebtoken to 9.0.0 ([#8420](https://github.com/parse-community/parse-server/issues/8420)) ([f5bfe45](https://github.com/parse-community/parse-server/commit/f5bfe4571e82b2b7440d41f3cff0d49937398164))
|
||||
|
||||
### Features
|
||||
|
||||
* Add option `schemaCacheTtl` for schema cache pulling as alternative to `enableSchemaHooks` ([#8436](https://github.com/parse-community/parse-server/issues/8436)) ([b3b76de](https://github.com/parse-community/parse-server/commit/b3b76de71b1d4265689d052e7837c38ec1fa4323))
|
||||
* Add Parse Server option `resetPasswordSuccessOnInvalidEmail` to choose success or error response on password reset with invalid email ([#7551](https://github.com/parse-community/parse-server/issues/7551)) ([e5d610e](https://github.com/parse-community/parse-server/commit/e5d610e5e487ddab86409409ac3d7362aba8f59b))
|
||||
* Deprecate LiveQuery `fields` option in favor of `keys` for semantic consistency ([#8388](https://github.com/parse-community/parse-server/issues/8388)) ([a49e323](https://github.com/parse-community/parse-server/commit/a49e323d5ae640bff1c6603ec37fdaddb9328dd1))
|
||||
* Export `AuthAdapter` to make it available for extension with custom authentication adapters ([#8443](https://github.com/parse-community/parse-server/issues/8443)) ([40c1961](https://github.com/parse-community/parse-server/commit/40c196153b8efa12ae384c1c0092b2ed60a260d6))
|
||||
|
||||
# [6.0.0-alpha.35](https://github.com/parse-community/parse-server/compare/6.0.0-alpha.34...6.0.0-alpha.35) (2023-02-27)
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
{
|
||||
"plugins": ["node_modules/jsdoc-babel", "plugins/markdown"],
|
||||
"babel": {
|
||||
"plugins": ["@babel/plugin-transform-flow-strip-types"]
|
||||
"plugins": ["@babel/plugin-transform-flow-strip-types"]
|
||||
},
|
||||
"source": {
|
||||
"include": ["./README.md", "./src/cloud-code", "./src/Options/docs.js", "./src/ParseServer.js", "./src/Adapters"],
|
||||
"include": [
|
||||
"README.md",
|
||||
"./src/cloud-code",
|
||||
"./src/Options/docs.js",
|
||||
"./src/ParseServer.js",
|
||||
"./src/Adapters"
|
||||
],
|
||||
"excludePattern": "(^|\\/|\\\\)_"
|
||||
},
|
||||
"templates": {
|
||||
@@ -17,7 +23,18 @@
|
||||
"monospaceLinks": false
|
||||
},
|
||||
"opts": {
|
||||
"template": "node_modules/@parse/minami",
|
||||
"recurse": true
|
||||
"encoding": "utf8",
|
||||
"readme": "./README.md",
|
||||
"recurse": true,
|
||||
"template": "./node_modules/clean-jsdoc-theme",
|
||||
"theme_opts": {
|
||||
"default_theme": "dark",
|
||||
"title": "<img src='../.github/parse-server-logo.png' class='logo'/>",
|
||||
"create_style": "header, .sidebar-section-title, .sidebar-title { color: #139cee !important } .logo { margin-left : 40px; margin-right: 40px }"
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"hardwrap": false,
|
||||
"idInHeadings": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
473
package-lock.json
generated
473
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "parse-server",
|
||||
"version": "6.1.0-beta.1",
|
||||
"version": "6.1.0-alpha.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "parse-server",
|
||||
"version": "6.1.0-beta.1",
|
||||
"version": "6.1.0-alpha.8",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -41,9 +41,10 @@
|
||||
"mustache": "4.2.0",
|
||||
"parse": "4.0.1",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"pg-monitor": "1.5.0",
|
||||
"pg-promise": "10.12.1",
|
||||
"pg-monitor": "2.0.0",
|
||||
"pg-promise": "11.3.0",
|
||||
"pluralize": "8.0.0",
|
||||
"rate-limit-redis": "3.0.1",
|
||||
"redis": "4.0.6",
|
||||
"semver": "7.3.8",
|
||||
"subscriptions-transport-ws": "0.11.0",
|
||||
@@ -64,7 +65,6 @@
|
||||
"@babel/plugin-proposal-object-rest-spread": "7.10.0",
|
||||
"@babel/plugin-transform-flow-strip-types": "7.9.0",
|
||||
"@babel/preset-env": "7.10.0",
|
||||
"@parse/minami": "1.0.0",
|
||||
"@saithodev/semantic-release-backmerge": "2.1.2",
|
||||
"@semantic-release/changelog": "5.0.1",
|
||||
"@semantic-release/commit-analyzer": "8.0.1",
|
||||
@@ -75,6 +75,7 @@
|
||||
"all-node-versions": "11.3.0",
|
||||
"apollo-upload-client": "17.0.0",
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
"clean-jsdoc-theme": "^4.2.7",
|
||||
"cross-env": "7.0.2",
|
||||
"deep-diff": "1.0.2",
|
||||
"eslint": "8.26.0",
|
||||
@@ -594,9 +595,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
|
||||
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
|
||||
"version": "7.21.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
|
||||
"integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -2287,6 +2288,18 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsdoc/salty": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz",
|
||||
"integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=v12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/triples": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz",
|
||||
@@ -2745,12 +2758,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.2.tgz",
|
||||
"integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g=="
|
||||
},
|
||||
"node_modules/@parse/minami": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@parse/minami/-/minami-1.0.0.tgz",
|
||||
"integrity": "sha512-Rw+p0WdOOypFPVJsmhyiI+Q056ZxdP2iAtObnU1DZrsvKZTf5x0B/0SjIt0hUgWp+COjqi/p17VdBU9IAD/NJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@parse/node-apn": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz",
|
||||
@@ -4060,11 +4067,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/assert-options": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.7.0.tgz",
|
||||
"integrity": "sha512-7q9uNH/Dh8gFgpIIb9ja8PJEWA5AQy3xnBC8jtKs8K/gNVCr1K6kIvlm59HUyYgvM7oEDoLzGgPcGd9FqhtXEQ==",
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.0.tgz",
|
||||
"integrity": "sha512-qSELrEaEz4sGwTs4Qh+swQkjiHAysC4rot21+jzXU86dJzNG+FDqBzyS3ohSoTRf4ZLA3FSwxQdiuNl5NXUtvA==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/assert-plus": {
|
||||
@@ -4686,6 +4693,16 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camel-case": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
|
||||
"integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"no-case": "^2.2.0",
|
||||
"upper-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
@@ -4858,6 +4875,59 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-css": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
|
||||
"integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"source-map": "~0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-css/node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-jsdoc-theme": {
|
||||
"version": "4.2.7",
|
||||
"resolved": "https://registry.npmjs.org/clean-jsdoc-theme/-/clean-jsdoc-theme-4.2.7.tgz",
|
||||
"integrity": "sha512-yLLxwTFw7N9/toUCcFmKkwJmv4LO2pQWYNETcU3Vv+n2al2L2ohb7xWoXLjp5m3OljC9b1m+o4adzY0YH6Ep4A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jsdoc/salty": "^0.2.4",
|
||||
"fs-extra": "^10.1.0",
|
||||
"html-minifier": "^4.0.0",
|
||||
"klaw-sync": "^6.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoid": "^3.3.4",
|
||||
"showdown": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jsdoc": ">=3.x <=4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-jsdoc-theme/node_modules/fs-extra": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-stack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||
@@ -8718,6 +8788,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@@ -8766,6 +8845,33 @@
|
||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/html-minifier": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
|
||||
"integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"camel-case": "^3.0.0",
|
||||
"clean-css": "^4.2.1",
|
||||
"commander": "^2.19.0",
|
||||
"he": "^1.2.0",
|
||||
"param-case": "^2.1.1",
|
||||
"relateurl": "^0.2.7",
|
||||
"uglify-js": "^3.5.1"
|
||||
},
|
||||
"bin": {
|
||||
"html-minifier": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/html-minifier/node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||
@@ -10120,6 +10226,15 @@
|
||||
"graceful-fs": "^4.1.9"
|
||||
}
|
||||
},
|
||||
"node_modules/klaw-sync": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/kuler": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
@@ -10885,6 +11000,12 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lower-case": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
|
||||
"integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lowercase-keys": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
|
||||
@@ -12227,6 +12348,15 @@
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
|
||||
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
|
||||
},
|
||||
"node_modules/no-case": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
|
||||
"integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lower-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abort-controller": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz",
|
||||
@@ -15901,6 +16031,15 @@
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/param-case": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
|
||||
"integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"no-case": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -16069,15 +16208,15 @@
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz",
|
||||
"integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==",
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.9.0.tgz",
|
||||
"integrity": "sha512-ZJM+qkEbtOHRuXjmvBtOgNOXOtLSbxiMiUVMgE4rV6Zwocy03RicCVvDXgx8l4Biwo8/qORUnEqn2fdQzV7KCg==",
|
||||
"dependencies": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.5.2",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-protocol": "^1.6.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
},
|
||||
@@ -16115,14 +16254,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pg-monitor": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-1.5.0.tgz",
|
||||
"integrity": "sha512-Zg5RpoYaz0zyRwAQWKrRxUZgzZ+/r4McMP4vEvg+qE8765SHAB1wHZL58uAjocG4WSK/NLP/zZhUuoyurw4l6Q==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-2.0.0.tgz",
|
||||
"integrity": "sha512-UqjhroM701sRrJHhXeF1OwNBGxkN9R0YgkVU8A46wWn3RwK/K7QDylChMoDxo8TmGp86CBP4ZSf+RK9vD8XyVA==",
|
||||
"dependencies": {
|
||||
"cli-color": "2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.6"
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-monitor/node_modules/cli-color": {
|
||||
@@ -16189,23 +16328,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pg-promise": {
|
||||
"version": "10.12.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.12.1.tgz",
|
||||
"integrity": "sha512-SiJkBUDGq7PNfJFJbWferodsSH+vLrhte0Q0kVgQbwlNYeKmp9Hhkr+357+5DWEuBGOHhSu1UQffSSf5HVqRtA==",
|
||||
"version": "11.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.3.0.tgz",
|
||||
"integrity": "sha512-A2CYmax5gsqVAO2N0ET9oPRCPX3kpKymj9qLVK7+jszlJL6l8uJDq/DGqLpxNi5VHwK7Dmm2WNRdrwkh1xuaxQ==",
|
||||
"dependencies": {
|
||||
"assert-options": "0.7.0",
|
||||
"pg": "8.8.0",
|
||||
"assert-options": "0.8.0",
|
||||
"pg": "8.9.0",
|
||||
"pg-minify": "1.6.2",
|
||||
"spex": "3.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz",
|
||||
"integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q=="
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
"version": "2.2.0",
|
||||
@@ -16746,6 +16885,17 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/rate-limit-redis": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-3.0.1.tgz",
|
||||
"integrity": "sha512-L6yhOUBrAZ8VEMX9DwlM3X6hfm8yq+gBO4LoOW7+JgmNq59zE7QmLz4v5VnwYPvLeSh/e7PDcrzUI3UumJw1iw==",
|
||||
"engines": {
|
||||
"node": ">= 14.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express-rate-limit": "^6"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
@@ -17308,6 +17458,15 @@
|
||||
"jsesc": "bin/jsesc"
|
||||
}
|
||||
},
|
||||
"node_modules/relateurl": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||
"integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/release-zalgo": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
|
||||
@@ -18151,6 +18310,31 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/showdown": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz",
|
||||
"integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"commander": "^9.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"showdown": "bin/showdown.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://www.paypal.me/tiviesantos"
|
||||
}
|
||||
},
|
||||
"node_modules/showdown/node_modules/commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
@@ -19610,7 +19794,6 @@
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
|
||||
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"uglifyjs": "bin/uglifyjs"
|
||||
},
|
||||
@@ -19836,6 +20019,12 @@
|
||||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/upper-case": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
|
||||
"integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -20810,9 +20999,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
|
||||
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA=="
|
||||
"version": "7.21.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
|
||||
"integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw=="
|
||||
},
|
||||
"@babel/plugin-proposal-object-rest-spread": {
|
||||
"version": "7.10.0",
|
||||
@@ -22021,6 +22210,15 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"@jsdoc/salty": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz",
|
||||
"integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
},
|
||||
"@napi-rs/triples": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz",
|
||||
@@ -22347,12 +22545,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.2.tgz",
|
||||
"integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g=="
|
||||
},
|
||||
"@parse/minami": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@parse/minami/-/minami-1.0.0.tgz",
|
||||
"integrity": "sha512-Rw+p0WdOOypFPVJsmhyiI+Q056ZxdP2iAtObnU1DZrsvKZTf5x0B/0SjIt0hUgWp+COjqi/p17VdBU9IAD/NJg==",
|
||||
"dev": true
|
||||
},
|
||||
"@parse/node-apn": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz",
|
||||
@@ -23386,9 +23578,9 @@
|
||||
}
|
||||
},
|
||||
"assert-options": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.7.0.tgz",
|
||||
"integrity": "sha512-7q9uNH/Dh8gFgpIIb9ja8PJEWA5AQy3xnBC8jtKs8K/gNVCr1K6kIvlm59HUyYgvM7oEDoLzGgPcGd9FqhtXEQ=="
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.0.tgz",
|
||||
"integrity": "sha512-qSELrEaEz4sGwTs4Qh+swQkjiHAysC4rot21+jzXU86dJzNG+FDqBzyS3ohSoTRf4ZLA3FSwxQdiuNl5NXUtvA=="
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
@@ -23865,6 +24057,16 @@
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
|
||||
},
|
||||
"camel-case": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
|
||||
"integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"no-case": "^2.2.0",
|
||||
"upper-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
@@ -23997,6 +24199,51 @@
|
||||
"static-extend": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
|
||||
"integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "~0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"clean-jsdoc-theme": {
|
||||
"version": "4.2.7",
|
||||
"resolved": "https://registry.npmjs.org/clean-jsdoc-theme/-/clean-jsdoc-theme-4.2.7.tgz",
|
||||
"integrity": "sha512-yLLxwTFw7N9/toUCcFmKkwJmv4LO2pQWYNETcU3Vv+n2al2L2ohb7xWoXLjp5m3OljC9b1m+o4adzY0YH6Ep4A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jsdoc/salty": "^0.2.4",
|
||||
"fs-extra": "^10.1.0",
|
||||
"html-minifier": "^4.0.0",
|
||||
"klaw-sync": "^6.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoid": "^3.3.4",
|
||||
"showdown": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"clean-stack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||
@@ -26989,6 +27236,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@@ -27030,6 +27283,29 @@
|
||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||
"dev": true
|
||||
},
|
||||
"html-minifier": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
|
||||
"integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camel-case": "^3.0.0",
|
||||
"clean-css": "^4.2.1",
|
||||
"commander": "^2.19.0",
|
||||
"he": "^1.2.0",
|
||||
"param-case": "^2.1.1",
|
||||
"relateurl": "^0.2.7",
|
||||
"uglify-js": "^3.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||
@@ -28074,6 +28350,15 @@
|
||||
"graceful-fs": "^4.1.9"
|
||||
}
|
||||
},
|
||||
"klaw-sync": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"kuler": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
@@ -28693,6 +28978,12 @@
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
|
||||
"integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==",
|
||||
"dev": true
|
||||
},
|
||||
"lowercase-keys": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
|
||||
@@ -29755,6 +30046,15 @@
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
|
||||
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
|
||||
},
|
||||
"no-case": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
|
||||
"integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lower-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node-abort-controller": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz",
|
||||
@@ -32407,6 +32707,15 @@
|
||||
"wcwidth": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"param-case": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
|
||||
"integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"no-case": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -32524,15 +32833,15 @@
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||
},
|
||||
"pg": {
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz",
|
||||
"integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==",
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.9.0.tgz",
|
||||
"integrity": "sha512-ZJM+qkEbtOHRuXjmvBtOgNOXOtLSbxiMiUVMgE4rV6Zwocy03RicCVvDXgx8l4Biwo8/qORUnEqn2fdQzV7KCg==",
|
||||
"requires": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.5.2",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-protocol": "^1.6.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
}
|
||||
@@ -32553,9 +32862,9 @@
|
||||
"integrity": "sha512-1KdmFGGTP6jplJoI8MfvRlfvMiyBivMRP7/ffh4a11RUFJ7kC2J0ZHlipoKiH/1hz+DVgceon9U2qbaHpPeyPg=="
|
||||
},
|
||||
"pg-monitor": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-1.5.0.tgz",
|
||||
"integrity": "sha512-Zg5RpoYaz0zyRwAQWKrRxUZgzZ+/r4McMP4vEvg+qE8765SHAB1wHZL58uAjocG4WSK/NLP/zZhUuoyurw4l6Q==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-monitor/-/pg-monitor-2.0.0.tgz",
|
||||
"integrity": "sha512-UqjhroM701sRrJHhXeF1OwNBGxkN9R0YgkVU8A46wWn3RwK/K7QDylChMoDxo8TmGp86CBP4ZSf+RK9vD8XyVA==",
|
||||
"requires": {
|
||||
"cli-color": "2.0.3"
|
||||
},
|
||||
@@ -32621,20 +32930,20 @@
|
||||
"requires": {}
|
||||
},
|
||||
"pg-promise": {
|
||||
"version": "10.12.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.12.1.tgz",
|
||||
"integrity": "sha512-SiJkBUDGq7PNfJFJbWferodsSH+vLrhte0Q0kVgQbwlNYeKmp9Hhkr+357+5DWEuBGOHhSu1UQffSSf5HVqRtA==",
|
||||
"version": "11.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.3.0.tgz",
|
||||
"integrity": "sha512-A2CYmax5gsqVAO2N0ET9oPRCPX3kpKymj9qLVK7+jszlJL6l8uJDq/DGqLpxNi5VHwK7Dmm2WNRdrwkh1xuaxQ==",
|
||||
"requires": {
|
||||
"assert-options": "0.7.0",
|
||||
"pg": "8.8.0",
|
||||
"assert-options": "0.8.0",
|
||||
"pg": "8.9.0",
|
||||
"pg-minify": "1.6.2",
|
||||
"spex": "3.2.0"
|
||||
}
|
||||
},
|
||||
"pg-protocol": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz",
|
||||
"integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q=="
|
||||
},
|
||||
"pg-types": {
|
||||
"version": "2.2.0",
|
||||
@@ -33032,6 +33341,12 @@
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||
},
|
||||
"rate-limit-redis": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-3.0.1.tgz",
|
||||
"integrity": "sha512-L6yhOUBrAZ8VEMX9DwlM3X6hfm8yq+gBO4LoOW7+JgmNq59zE7QmLz4v5VnwYPvLeSh/e7PDcrzUI3UumJw1iw==",
|
||||
"requires": {}
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
@@ -33491,6 +33806,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"relateurl": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||
"integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
|
||||
"dev": true
|
||||
},
|
||||
"release-zalgo": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
|
||||
@@ -34130,6 +34451,23 @@
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||
},
|
||||
"showdown": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz",
|
||||
"integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^9.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
@@ -35288,8 +35626,7 @@
|
||||
"version": "3.17.4",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
|
||||
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"unbzip2-stream": {
|
||||
"version": "1.4.3",
|
||||
@@ -35451,6 +35788,12 @@
|
||||
"picocolors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"upper-case": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
|
||||
"integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "parse-server",
|
||||
"version": "6.1.0-beta.1",
|
||||
"version": "6.1.0-alpha.8",
|
||||
"description": "An express module providing a Parse-compatible API server",
|
||||
"main": "lib/index.js",
|
||||
"repository": {
|
||||
@@ -50,9 +50,10 @@
|
||||
"mustache": "4.2.0",
|
||||
"parse": "4.0.1",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"pg-monitor": "1.5.0",
|
||||
"pg-promise": "10.12.1",
|
||||
"pg-monitor": "2.0.0",
|
||||
"pg-promise": "11.3.0",
|
||||
"pluralize": "8.0.0",
|
||||
"rate-limit-redis": "3.0.1",
|
||||
"redis": "4.0.6",
|
||||
"semver": "7.3.8",
|
||||
"subscriptions-transport-ws": "0.11.0",
|
||||
@@ -70,7 +71,6 @@
|
||||
"@babel/plugin-proposal-object-rest-spread": "7.10.0",
|
||||
"@babel/plugin-transform-flow-strip-types": "7.9.0",
|
||||
"@babel/preset-env": "7.10.0",
|
||||
"@parse/minami": "1.0.0",
|
||||
"@saithodev/semantic-release-backmerge": "2.1.2",
|
||||
"@semantic-release/changelog": "5.0.1",
|
||||
"@semantic-release/commit-analyzer": "8.0.1",
|
||||
@@ -81,6 +81,7 @@
|
||||
"all-node-versions": "11.3.0",
|
||||
"apollo-upload-client": "17.0.0",
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
"clean-jsdoc-theme": "4.2.7",
|
||||
"cross-env": "7.0.2",
|
||||
"deep-diff": "1.0.2",
|
||||
"eslint": "8.26.0",
|
||||
|
||||
@@ -161,6 +161,9 @@ function mapperFor(elt, t) {
|
||||
if (type == 'NumberOrBoolean') {
|
||||
return wrap(t.identifier('numberOrBooleanParser'));
|
||||
}
|
||||
if (type === 'StringOrStringArray') {
|
||||
return wrap(t.identifier('arrayParser'));
|
||||
}
|
||||
return wrap(t.identifier('objectParser'));
|
||||
}
|
||||
}
|
||||
@@ -278,6 +281,9 @@ function inject(t, list) {
|
||||
const adapterType = elt.typeAnnotation.typeParameters.params[0].id.name;
|
||||
type = `Adapter<${adapterType}>`;
|
||||
}
|
||||
if (type === 'StringOrStringArray') {
|
||||
type = 'String|String[]';
|
||||
}
|
||||
comments += ` * @property {${type}} ${elt.name} ${elt.help}\n`;
|
||||
const obj = t.objectExpression(props);
|
||||
return t.objectProperty(t.stringLiteral(elt.name), obj);
|
||||
|
||||
@@ -59,6 +59,19 @@ describe('Auth Adapter features', () => {
|
||||
validateLogin: () => Promise.resolve(),
|
||||
};
|
||||
|
||||
const modernAdapter3 = {
|
||||
validateAppId: () => Promise.resolve(),
|
||||
validateSetUp: () => Promise.resolve(),
|
||||
validateUpdate: () => Promise.resolve(),
|
||||
validateLogin: () => Promise.resolve(),
|
||||
validateOptions: () => Promise.resolve(),
|
||||
afterFind() {
|
||||
return {
|
||||
foo: 'bar',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const wrongAdapter = {
|
||||
validateAppId: () => Promise.resolve(),
|
||||
};
|
||||
@@ -332,6 +345,30 @@ describe('Auth Adapter features', () => {
|
||||
expect(user.getSessionToken()).toBeDefined();
|
||||
});
|
||||
|
||||
it('should strip out authData if required', async () => {
|
||||
const spy = spyOn(modernAdapter3, 'validateOptions').and.callThrough();
|
||||
const afterSpy = spyOn(modernAdapter3, 'afterFind').and.callThrough();
|
||||
await reconfigureServer({ auth: { modernAdapter3 } });
|
||||
const user = new Parse.User();
|
||||
await user.save({ authData: { modernAdapter3: { id: 'modernAdapter3Data' } } });
|
||||
await user.fetch({ sessionToken: user.getSessionToken() });
|
||||
const authData = user.get('authData').modernAdapter3;
|
||||
expect(authData).toEqual({ foo: 'bar' });
|
||||
for (const call of afterSpy.calls.all()) {
|
||||
const args = call.args[0];
|
||||
if (args.user) {
|
||||
user._objCount = args.user._objCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(afterSpy).toHaveBeenCalledWith(
|
||||
{ ip: '127.0.0.1', user, master: false },
|
||||
{ id: 'modernAdapter3Data' },
|
||||
undefined
|
||||
);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw if no triggers found', async () => {
|
||||
await reconfigureServer({ auth: { wrongAdapter } });
|
||||
const user = new Parse.User();
|
||||
|
||||
@@ -45,10 +45,6 @@ describe('Idempotency', () => {
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000;
|
||||
});
|
||||
|
||||
// Tests
|
||||
it('should enforce idempotency for cloud code function', async () => {
|
||||
let counter = 0;
|
||||
|
||||
@@ -287,6 +287,35 @@ describe('middlewares', () => {
|
||||
expect(headers['Access-Control-Allow-Origin']).toEqual('https://parseplatform.org/');
|
||||
});
|
||||
|
||||
it('should support multiple origins if several are defined in allowOrigin as an array', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
allowOrigin: ['https://a.com', 'https://b.com', 'https://c.com'],
|
||||
});
|
||||
const headers = {};
|
||||
const res = {
|
||||
header: (key, value) => {
|
||||
headers[key] = value;
|
||||
},
|
||||
};
|
||||
const allowCrossDomain = middlewares.allowCrossDomain(fakeReq.body._ApplicationId);
|
||||
// Test with the first domain
|
||||
fakeReq.headers.origin = 'https://a.com';
|
||||
allowCrossDomain(fakeReq, res, () => {});
|
||||
expect(headers['Access-Control-Allow-Origin']).toEqual('https://a.com');
|
||||
// Test with the second domain
|
||||
fakeReq.headers.origin = 'https://b.com';
|
||||
allowCrossDomain(fakeReq, res, () => {});
|
||||
expect(headers['Access-Control-Allow-Origin']).toEqual('https://b.com');
|
||||
// Test with the third domain
|
||||
fakeReq.headers.origin = 'https://c.com';
|
||||
allowCrossDomain(fakeReq, res, () => {});
|
||||
expect(headers['Access-Control-Allow-Origin']).toEqual('https://c.com');
|
||||
// Test with an unauthorized domain
|
||||
fakeReq.headers.origin = 'https://unauthorized.com';
|
||||
allowCrossDomain(fakeReq, res, () => {});
|
||||
expect(headers['Access-Control-Allow-Origin']).toEqual('https://a.com');
|
||||
});
|
||||
|
||||
it('should use user provided on field userFromJWT', done => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
|
||||
@@ -248,6 +248,10 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
|
||||
expect(object.date[0] instanceof Date).toBeTrue();
|
||||
expect(object.bar.date[0] instanceof Date).toBeTrue();
|
||||
expect(object.foo.test.date[0] instanceof Date).toBeTrue();
|
||||
const obj = await new Parse.Query('MyClass').first({ useMasterKey: true });
|
||||
expect(obj.get('date')[0] instanceof Date).toBeTrue();
|
||||
expect(obj.get('bar').date[0] instanceof Date).toBeTrue();
|
||||
expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue();
|
||||
});
|
||||
|
||||
it('handles updating a single object with array, object date', done => {
|
||||
|
||||
@@ -6,6 +6,7 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
|
||||
});
|
||||
it('can connect', async () => {
|
||||
await reconfigureServer({
|
||||
appId: 'redis_live_query',
|
||||
startLiveQueryServer: true,
|
||||
liveQuery: {
|
||||
classNames: ['TestObject'],
|
||||
@@ -36,6 +37,7 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
|
||||
|
||||
it('can call connect twice', async () => {
|
||||
const server = await reconfigureServer({
|
||||
appId: 'redis_live_query',
|
||||
startLiveQueryServer: true,
|
||||
liveQuery: {
|
||||
classNames: ['TestObject'],
|
||||
|
||||
@@ -115,6 +115,7 @@ describe('ParseLiveQueryServer', function () {
|
||||
});
|
||||
|
||||
describe_only_db('mongo')('initialization', () => {
|
||||
beforeEach(() => reconfigureServer({ appId: 'mongo_init_test' }));
|
||||
it('can be initialized through ParseServer without liveQueryServerOptions', async () => {
|
||||
const parseServer = await ParseServer.startApp({
|
||||
appId: 'hello',
|
||||
@@ -754,6 +755,49 @@ describe('ParseLiveQueryServer', function () {
|
||||
parseLiveQueryServer._onAfterSave(message);
|
||||
});
|
||||
|
||||
it('sends correct object for dates', async () => {
|
||||
jasmine.restoreLibrary('../lib/LiveQuery/QueryTools', 'matchesQuery');
|
||||
|
||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||
|
||||
const date = new Date();
|
||||
const message = {
|
||||
currentParseObject: {
|
||||
date: { __type: 'Date', iso: date.toISOString() },
|
||||
__type: 'Object',
|
||||
key: 'value',
|
||||
className: testClassName,
|
||||
},
|
||||
};
|
||||
// Add mock client
|
||||
const clientId = 1;
|
||||
const client = addMockClient(parseLiveQueryServer, clientId);
|
||||
|
||||
const requestId2 = 2;
|
||||
|
||||
await addMockSubscription(parseLiveQueryServer, clientId, requestId2);
|
||||
|
||||
parseLiveQueryServer._matchesACL = function () {
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
|
||||
parseLiveQueryServer._inflateParseObject(message);
|
||||
parseLiveQueryServer._onAfterSave(message);
|
||||
|
||||
// Make sure we send leave and enter command to client
|
||||
await timeout();
|
||||
|
||||
expect(client.pushCreate).toHaveBeenCalledWith(
|
||||
requestId2,
|
||||
{
|
||||
className: 'TestObject',
|
||||
key: 'value',
|
||||
date: { __type: 'Date', iso: date.toISOString() },
|
||||
},
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
it('can handle object save command which does not match any subscription', async done => {
|
||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||
// Make mock request message
|
||||
@@ -1138,8 +1182,7 @@ describe('ParseLiveQueryServer', function () {
|
||||
expect(toSend.original).toBeUndefined();
|
||||
expect(spy).toHaveBeenCalledWith({
|
||||
usage: 'Subscribing using fields parameter',
|
||||
solution:
|
||||
`Subscribe using "keys" instead.`,
|
||||
solution: `Subscribe using "keys" instead.`,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1945,6 +1988,7 @@ describe('ParseLiveQueryServer', function () {
|
||||
} else {
|
||||
subscription.clientRequestIds = new Map([[clientId, [requestId]]]);
|
||||
}
|
||||
subscription.query = query.where;
|
||||
return subscription;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,13 +27,13 @@ const baseURI = 'postgres://username:password@localhost:5432/db-name';
|
||||
const testfile = fs.readFileSync('./Dockerfile').toString();
|
||||
const dbOptionsTest = {};
|
||||
dbOptionsTest[
|
||||
`${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=10`
|
||||
`${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=12`
|
||||
] = {
|
||||
ssl: true,
|
||||
binary: true,
|
||||
application_name: 'app_name',
|
||||
fallback_application_name: 'f_app_name',
|
||||
poolSize: 10,
|
||||
max: 12,
|
||||
};
|
||||
dbOptionsTest[`${baseURI}?ssl=&binary=aa`] = {
|
||||
binary: false,
|
||||
@@ -83,6 +83,20 @@ describe('PostgresConfigParser.getDatabaseOptionsFromURI', () => {
|
||||
it('sets the poolSize to 10 if the it is not a number', () => {
|
||||
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=sdf`);
|
||||
|
||||
expect(result.poolSize).toEqual(10);
|
||||
expect(result.max).toEqual(10);
|
||||
});
|
||||
|
||||
it('sets the max to 10 if the it is not a number', () => {
|
||||
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?&max=sdf`);
|
||||
|
||||
expect(result.poolSize).toBeUndefined();
|
||||
expect(result.max).toEqual(10);
|
||||
});
|
||||
|
||||
it('max should take precedence over poolSize', () => {
|
||||
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=20&max=12`);
|
||||
|
||||
expect(result.poolSize).toBeUndefined();
|
||||
expect(result.max).toEqual(12);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default;
|
||||
describe('rate limit', () => {
|
||||
it('can limit cloud functions', async () => {
|
||||
Parse.Cloud.define('test', () => 'Abc');
|
||||
@@ -388,4 +389,33 @@ describe('rate limit', () => {
|
||||
})
|
||||
).toBeRejectedWith(`Invalid rate limit option "path"`);
|
||||
});
|
||||
describe_only(() => {
|
||||
return process.env.PARSE_SERVER_TEST_CACHE === 'redis';
|
||||
})('with RedisCache', function () {
|
||||
it('does work with cache', async () => {
|
||||
await reconfigureServer({
|
||||
rateLimit: [
|
||||
{
|
||||
requestPath: '/classes/*',
|
||||
requestTimeWindow: 10000,
|
||||
requestCount: 1,
|
||||
errorResponseMessage: 'Too many requests',
|
||||
includeInternalRequests: true,
|
||||
redisUrl: 'redis://localhost:6379',
|
||||
},
|
||||
],
|
||||
});
|
||||
const obj = new Parse.Object('Test');
|
||||
await obj.save();
|
||||
await expectAsync(obj.save()).toBeRejectedWith(
|
||||
new Parse.Error(Parse.Error.CONNECTION_FAILED, 'Too many requests')
|
||||
);
|
||||
const cache = new RedisCacheAdapter();
|
||||
await cache.connect();
|
||||
const value = await cache.get('rl:127.0.0.1');
|
||||
expect(value).toEqual(2);
|
||||
const ttl = await cache.client.ttl('rl:127.0.0.1');
|
||||
expect(ttl).toEqual(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -198,6 +198,10 @@ beforeAll(async () => {
|
||||
Parse.serverURL = 'http://localhost:' + port + '/1';
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000;
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
const afterLogOut = async () => {
|
||||
if (Object.keys(openConnections).length > 0) {
|
||||
@@ -214,6 +218,7 @@ afterEach(function (done) {
|
||||
done();
|
||||
};
|
||||
Parse.Cloud._removeAllHooks();
|
||||
Parse.CoreManager.getLiveQueryController().setDefaultLiveQueryClient();
|
||||
defaults.protectedFields = { _User: { '*': ['email'] } };
|
||||
databaseAdapter
|
||||
.getAllClasses()
|
||||
|
||||
@@ -558,7 +558,7 @@ describe('server', () => {
|
||||
});
|
||||
|
||||
it('can get starting state', async () => {
|
||||
await reconfigureServer({ appId: 'test2', silent: false });
|
||||
await reconfigureServer({ appId: 'test2' });
|
||||
const parseServer = new ParseServer.ParseServer({
|
||||
...defaultConfiguration,
|
||||
appId: 'test2',
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*eslint no-unused-vars: "off"*/
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface AnalyticsAdapter
|
||||
* @module Adapters
|
||||
*/
|
||||
export class AnalyticsAdapter {
|
||||
/**
|
||||
|
||||
@@ -93,6 +93,24 @@ export class AuthAdapter {
|
||||
challenge(challengeData, authData, options, request) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when auth data is fetched
|
||||
* @param {Object} authData authData
|
||||
* @param {Object} options additional adapter options
|
||||
* @returns {Promise<Object>} Any overrides required to authData
|
||||
*/
|
||||
afterFind(authData, options) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when the adapter is first attached to Parse Server
|
||||
* @param {Object} options Adapter Options
|
||||
*/
|
||||
validateOptions(options) {
|
||||
/* */
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthAdapter;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import loadAdapter from '../AdapterLoader';
|
||||
import Parse from 'parse/node';
|
||||
import AuthAdapter from './AuthAdapter';
|
||||
|
||||
const apple = require('./apple');
|
||||
const gcenter = require('./gcenter');
|
||||
@@ -153,28 +154,46 @@ function loadAuthAdapter(provider, authOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
const adapter = Object.assign({}, defaultAdapter);
|
||||
const adapter =
|
||||
defaultAdapter instanceof AuthAdapter ? defaultAdapter : Object.assign({}, defaultAdapter);
|
||||
const keys = [
|
||||
'validateAuthData',
|
||||
'validateAppId',
|
||||
'validateSetUp',
|
||||
'validateLogin',
|
||||
'validateUpdate',
|
||||
'challenge',
|
||||
'validateOptions',
|
||||
'policy',
|
||||
'afterFind',
|
||||
];
|
||||
const defaultAuthAdapter = new AuthAdapter();
|
||||
keys.forEach(key => {
|
||||
const existing = adapter?.[key];
|
||||
if (
|
||||
existing &&
|
||||
typeof existing === 'function' &&
|
||||
existing.toString() === defaultAuthAdapter[key].toString()
|
||||
) {
|
||||
adapter[key] = null;
|
||||
}
|
||||
});
|
||||
const appIds = providerOptions ? providerOptions.appIds : undefined;
|
||||
|
||||
// Try the configuration methods
|
||||
if (providerOptions) {
|
||||
const optionalAdapter = loadAdapter(providerOptions, undefined, providerOptions);
|
||||
if (optionalAdapter) {
|
||||
[
|
||||
'validateAuthData',
|
||||
'validateAppId',
|
||||
'validateSetUp',
|
||||
'validateLogin',
|
||||
'validateUpdate',
|
||||
'challenge',
|
||||
'policy',
|
||||
].forEach(key => {
|
||||
keys.forEach(key => {
|
||||
if (optionalAdapter[key]) {
|
||||
adapter[key] = optionalAdapter[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (adapter.validateOptions) {
|
||||
adapter.validateOptions(providerOptions);
|
||||
}
|
||||
|
||||
return { adapter, appIds, providerOptions };
|
||||
}
|
||||
@@ -195,9 +214,40 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) {
|
||||
return { validator: authDataValidator(provider, adapter, appIds, providerOptions), adapter };
|
||||
};
|
||||
|
||||
const runAfterFind = async (req, authData) => {
|
||||
if (!authData) {
|
||||
return;
|
||||
}
|
||||
const adapters = Object.keys(authData);
|
||||
await Promise.all(
|
||||
adapters.map(async provider => {
|
||||
const authAdapter = getValidatorForProvider(provider);
|
||||
if (!authAdapter) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
adapter: { afterFind },
|
||||
providerOptions,
|
||||
} = authAdapter;
|
||||
if (afterFind && typeof afterFind === 'function') {
|
||||
const requestObject = {
|
||||
ip: req.config.ip,
|
||||
user: req.auth.user,
|
||||
master: req.auth.isMaster,
|
||||
};
|
||||
const result = afterFind(requestObject, authData[provider], providerOptions);
|
||||
if (result) {
|
||||
authData[provider] = result;
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return Object.freeze({
|
||||
getValidatorForProvider,
|
||||
setEnableAnonymousUsers,
|
||||
runAfterFind,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*eslint no-unused-vars: "off"*/
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface CacheAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
*/
|
||||
export class CacheAdapter {
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*eslint no-unused-vars: "off"*/
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface MailAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
* Mail Adapter prototype
|
||||
* A MailAdapter should implement at least sendMail()
|
||||
*/
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
import type { Config } from '../../Config';
|
||||
import Parse from 'parse/node';
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface FilesAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
*/
|
||||
export class FilesAdapter {
|
||||
/** Responsible for storing the file in order to be retrieved later by its filename
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*eslint no-unused-vars: "off"*/
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface LoggerAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
* Logger Adapter
|
||||
* Allows you to change the logger mechanism
|
||||
* Default is WinstonLoggerAdapter.js
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*eslint no-unused-vars: "off"*/
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface PubSubAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
*/
|
||||
export class PubSubAdapter {
|
||||
/**
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
// android push and APNS for ios push.
|
||||
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface PushAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
*/
|
||||
export class PushAdapter {
|
||||
/**
|
||||
|
||||
@@ -188,6 +188,16 @@ const transformInteriorValue = restValue => {
|
||||
// Handle atomic values
|
||||
var value = transformInteriorAtom(restValue);
|
||||
if (value !== CannotTransform) {
|
||||
if (value && typeof value === 'object') {
|
||||
if (value instanceof Date) {
|
||||
return value;
|
||||
}
|
||||
if (value instanceof Array) {
|
||||
value = value.map(transformInteriorValue);
|
||||
} else {
|
||||
value = mapValues(value, transformInteriorValue);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1014,9 +1024,6 @@ function mapValues(object, iterator) {
|
||||
const result = {};
|
||||
Object.keys(object).forEach(key => {
|
||||
result[key] = iterator(object[key]);
|
||||
if (result[key] && JSON.stringify(result[key]).includes(`"__type"`)) {
|
||||
result[key] = mapValues(object[key], iterator);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ function getDatabaseOptionsFromURI(uri) {
|
||||
databaseOptions.fallback_application_name = queryParams.fallback_application_name;
|
||||
|
||||
if (queryParams.poolSize) {
|
||||
databaseOptions.poolSize = parseInt(queryParams.poolSize) || 10;
|
||||
databaseOptions.max = parseInt(queryParams.poolSize) || 10;
|
||||
}
|
||||
if (queryParams.max) {
|
||||
databaseOptions.max = parseInt(queryParams.max) || 10;
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
// Default is WSAdapter. The above functions will be binded.
|
||||
|
||||
/**
|
||||
* @module Adapters
|
||||
*/
|
||||
/**
|
||||
* @interface WSSAdapter
|
||||
* @interface
|
||||
* @memberof module:Adapters
|
||||
*/
|
||||
export class WSSAdapter {
|
||||
/**
|
||||
|
||||
@@ -626,6 +626,16 @@ export class Config {
|
||||
return new Date(now.getTime() + this.sessionLength * 1000);
|
||||
}
|
||||
|
||||
unregisterRateLimiters() {
|
||||
let i = this.rateLimits?.length;
|
||||
while (i--) {
|
||||
const limit = this.rateLimits[i];
|
||||
if (limit.cloud) {
|
||||
this.rateLimits.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get invalidLinkURL() {
|
||||
return this.customPages.invalidLink || `${this.publicServerURL}/apps/invalid_link.html`;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import UserRouter from '../Routers/UsersRouter';
|
||||
import DatabaseController from '../Controllers/DatabaseController';
|
||||
import { isDeepStrictEqual } from 'util';
|
||||
import Deprecator from '../Deprecator/Deprecator';
|
||||
import deepcopy from 'deepcopy';
|
||||
|
||||
class ParseLiveQueryServer {
|
||||
clients: Map;
|
||||
@@ -496,7 +497,7 @@ class ParseLiveQueryServer {
|
||||
if (!parseObject) {
|
||||
return false;
|
||||
}
|
||||
return matchesQuery(parseObject, subscription.query);
|
||||
return matchesQuery(deepcopy(parseObject), subscription.query);
|
||||
}
|
||||
|
||||
async _clearCachedRoles(userId: string) {
|
||||
|
||||
@@ -81,7 +81,9 @@ module.exports.ParseServerOptions = {
|
||||
},
|
||||
allowOrigin: {
|
||||
env: 'PARSE_SERVER_ALLOW_ORIGIN',
|
||||
help: 'Sets the origin to Access-Control-Allow-Origin',
|
||||
help:
|
||||
'Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins.',
|
||||
action: parsers.arrayParser,
|
||||
},
|
||||
analyticsAdapter: {
|
||||
env: 'PARSE_SERVER_ANALYTICS_ADAPTER',
|
||||
@@ -557,6 +559,11 @@ module.exports.RateLimitOptions = {
|
||||
action: parsers.booleanParser,
|
||||
default: false,
|
||||
},
|
||||
redisUrl: {
|
||||
env: 'PARSE_SERVER_RATE_LIMIT_REDIS_URL',
|
||||
help:
|
||||
'Optional, the URL of the Redis server to store rate limit data. This allows to rate limit requests for multiple servers by calculating the sum of all requests across all servers. This is useful if multiple servers are processing requests behind a load balancer. For example, the limit of 10 requests is reached if each of 2 servers processed 5 requests.',
|
||||
},
|
||||
requestCount: {
|
||||
env: 'PARSE_SERVER_RATE_LIMIT_REQUEST_COUNT',
|
||||
help:
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* @property {Boolean} allowCustomObjectId Enable (or disable) custom objectId
|
||||
* @property {Boolean} allowExpiredAuthDataToken Allow a user to log in even if the 3rd party authentication token that was used to sign in to their account has expired. If this is set to `false`, then the token will be validated every time the user signs in to their account. This refers to the token that is stored in the `_User.authData` field. Defaults to `true`.
|
||||
* @property {String[]} allowHeaders Add headers to Access-Control-Allow-Headers
|
||||
* @property {String} allowOrigin Sets the origin to Access-Control-Allow-Origin
|
||||
* @property {String|String[]} allowOrigin Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins.
|
||||
* @property {Adapter<AnalyticsAdapter>} analyticsAdapter Adapter module for the analytics
|
||||
* @property {String} appId Your Parse Application ID
|
||||
* @property {String} appName Sets the app name
|
||||
@@ -104,6 +104,7 @@
|
||||
* @property {String} errorResponseMessage The error message that should be returned in the body of the HTTP 429 response when the rate limit is hit. Default is `Too many requests.`.
|
||||
* @property {Boolean} includeInternalRequests Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks.
|
||||
* @property {Boolean} includeMasterKey Optional, if `true` the rate limit will also apply to requests using the `masterKey`, default is `false`. Note that a public Cloud Code function that triggers internal requests using the `masterKey` may circumvent rate limiting and be vulnerable to attacks.
|
||||
* @property {String} redisUrl Optional, the URL of the Redis server to store rate limit data. This allows to rate limit requests for multiple servers by calculating the sum of all requests across all servers. This is useful if multiple servers are processing requests behind a load balancer. For example, the limit of 10 requests is reached if each of 2 servers processed 5 requests.
|
||||
* @property {Number} requestCount The number of requests that can be made per IP address within the time window set in `requestTimeWindow` before the rate limit is applied.
|
||||
* @property {String[]} requestMethods Optional, the HTTP request methods to which the rate limit should be applied, default is all methods.
|
||||
* @property {String} requestPath The path of the API route to be rate limited. Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expression. See: https://expressjs.com/en/guide/routing.html
|
||||
|
||||
@@ -35,6 +35,7 @@ type Adapter<T> = string | any | T;
|
||||
type NumberOrBoolean = number | boolean;
|
||||
type NumberOrString = number | string;
|
||||
type ProtectedFields = any;
|
||||
type StringOrStringArray = string | string[];
|
||||
type RequestKeywordDenylist = {
|
||||
key: string | any,
|
||||
value: any,
|
||||
@@ -61,8 +62,8 @@ export interface ParseServerOptions {
|
||||
appName: ?string;
|
||||
/* Add headers to Access-Control-Allow-Headers */
|
||||
allowHeaders: ?(string[]);
|
||||
/* Sets the origin to Access-Control-Allow-Origin */
|
||||
allowOrigin: ?string;
|
||||
/* Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins. */
|
||||
allowOrigin: ?StringOrStringArray;
|
||||
/* Adapter module for the analytics */
|
||||
analyticsAdapter: ?Adapter<AnalyticsAdapter>;
|
||||
/* Adapter module for the files sub-system */
|
||||
@@ -320,6 +321,9 @@ export interface RateLimitOptions {
|
||||
/* Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks.
|
||||
:DEFAULT: false */
|
||||
includeInternalRequests: ?boolean;
|
||||
/* Optional, the URL of the Redis server to store rate limit data. This allows to rate limit requests for multiple servers by calculating the sum of all requests across all servers. This is useful if multiple servers are processing requests behind a load balancer. For example, the limit of 10 requests is reached if each of 2 servers processed 5 requests.
|
||||
*/
|
||||
redisUrl: ?string;
|
||||
}
|
||||
|
||||
export interface SecurityOptions {
|
||||
|
||||
@@ -223,6 +223,9 @@ RestQuery.prototype.execute = function (executeOptions) {
|
||||
.then(() => {
|
||||
return this.runAfterFindTrigger();
|
||||
})
|
||||
.then(() => {
|
||||
return this.handleAuthAdapters();
|
||||
})
|
||||
.then(() => {
|
||||
return this.response;
|
||||
});
|
||||
@@ -842,6 +845,20 @@ RestQuery.prototype.runAfterFindTrigger = function () {
|
||||
});
|
||||
};
|
||||
|
||||
RestQuery.prototype.handleAuthAdapters = async function () {
|
||||
if (this.className !== '_User' || this.findOptions.explain) {
|
||||
return;
|
||||
}
|
||||
await Promise.all(
|
||||
this.response.results.map(result =>
|
||||
this.config.authDataManager.runAfterFind(
|
||||
{ config: this.config, auth: this.auth },
|
||||
result.authData
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
// Adds included values to the response.
|
||||
// Path is a list of field names.
|
||||
// Returns a promise for an augmented response.
|
||||
|
||||
@@ -292,6 +292,7 @@ export class UsersRouter extends ClassesRouter {
|
||||
if (authDataResponse) {
|
||||
user.authDataResponse = authDataResponse;
|
||||
}
|
||||
await req.config.authDataManager.runAfterFind(req, user.authData);
|
||||
|
||||
return { response: user };
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { isFunction, isString } from 'lodash';
|
||||
|
||||
/**
|
||||
* A security check.
|
||||
* @class Check
|
||||
* @class
|
||||
*/
|
||||
class Check {
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/**
|
||||
* @module SecurityCheck
|
||||
*/
|
||||
|
||||
/**
|
||||
* A group of security checks.
|
||||
* @interface CheckGroup
|
||||
* @interface
|
||||
* @memberof module:SecurityCheck
|
||||
*/
|
||||
class CheckGroup {
|
||||
constructor() {
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* @module SecurityCheck
|
||||
*/
|
||||
|
||||
import { Check } from '../Check';
|
||||
import CheckGroup from '../CheckGroup';
|
||||
import Config from '../../Config';
|
||||
@@ -9,7 +5,8 @@ import Parse from 'parse/node';
|
||||
|
||||
/**
|
||||
* The security checks group for Parse Server configuration.
|
||||
* Checks common Parse Server parameters such as access keys.
|
||||
* Checks common Parse Server parameters such as access keys
|
||||
* @memberof module:SecurityCheck
|
||||
*/
|
||||
class CheckGroupDatabase extends CheckGroup {
|
||||
setName() {
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* @module SecurityCheck
|
||||
*/
|
||||
|
||||
import { Check } from '../Check';
|
||||
import CheckGroup from '../CheckGroup';
|
||||
import Config from '../../Config';
|
||||
@@ -10,6 +6,7 @@ import Parse from 'parse/node';
|
||||
/**
|
||||
* The security checks group for Parse Server configuration.
|
||||
* Checks common Parse Server parameters such as access keys.
|
||||
* @memberof module:SecurityCheck
|
||||
*/
|
||||
class CheckGroupServerConfig extends CheckGroup {
|
||||
setName() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @module SecurityCheck
|
||||
* @memberof module:SecurityCheck
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* @module SecurityCheck
|
||||
*/
|
||||
|
||||
import Utils from '../Utils';
|
||||
import { CheckState } from './Check';
|
||||
import * as CheckGroups from './CheckGroups/CheckGroups';
|
||||
@@ -10,6 +6,7 @@ import { isArray, isBoolean } from 'lodash';
|
||||
|
||||
/**
|
||||
* The security check runner.
|
||||
* @memberof module:SecurityCheck
|
||||
*/
|
||||
class CheckRunner {
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import AppCache from './cache';
|
||||
import SchemaCache from './Adapters/Cache/SchemaCache';
|
||||
|
||||
/**
|
||||
* Destroys all data in the database
|
||||
@@ -11,11 +12,17 @@ export function destroyAllDataPermanently(fast) {
|
||||
return Promise.all(
|
||||
Object.keys(AppCache.cache).map(appId => {
|
||||
const app = AppCache.get(appId);
|
||||
if (app.databaseController) {
|
||||
return app.databaseController.deleteEverything(fast);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
const deletePromises = [];
|
||||
if (app.cacheAdapter) {
|
||||
deletePromises.push(app.cacheAdapter.clear());
|
||||
}
|
||||
if (app.databaseController) {
|
||||
deletePromises.push(app.databaseController.deleteEverything(fast));
|
||||
} else if (app.databaseAdapter) {
|
||||
SchemaCache.clear();
|
||||
deletePromises.push(app.databaseAdapter.deleteAllClasses(fast));
|
||||
}
|
||||
return Promise.all(deletePromises);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,8 @@ ParseCloud.define = function (functionName, handler, validationHandler) {
|
||||
if (validationHandler && validationHandler.rateLimit) {
|
||||
addRateLimit(
|
||||
{ requestPath: `/functions/${functionName}`, ...validationHandler.rateLimit },
|
||||
Parse.applicationId
|
||||
Parse.applicationId,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -191,7 +192,8 @@ ParseCloud.beforeSave = function (parseClass, handler, validationHandler) {
|
||||
requestMethods: ['POST', 'PUT'],
|
||||
...validationHandler.rateLimit,
|
||||
},
|
||||
Parse.applicationId
|
||||
Parse.applicationId,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -237,7 +239,8 @@ ParseCloud.beforeDelete = function (parseClass, handler, validationHandler) {
|
||||
requestMethods: 'DELETE',
|
||||
...validationHandler.rateLimit,
|
||||
},
|
||||
Parse.applicationId
|
||||
Parse.applicationId,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -278,7 +281,8 @@ ParseCloud.beforeLogin = function (handler, validationHandler) {
|
||||
if (validationHandler && validationHandler.rateLimit) {
|
||||
addRateLimit(
|
||||
{ requestPath: `/login`, requestMethods: 'POST', ...validationHandler.rateLimit },
|
||||
Parse.applicationId
|
||||
Parse.applicationId,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -456,7 +460,8 @@ ParseCloud.beforeFind = function (parseClass, handler, validationHandler) {
|
||||
requestMethods: 'GET',
|
||||
...validationHandler.rateLimit,
|
||||
},
|
||||
Parse.applicationId
|
||||
Parse.applicationId,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -761,6 +766,8 @@ ParseCloud.afterLiveQueryEvent = function (parseClass, handler, validationHandle
|
||||
|
||||
ParseCloud._removeAllHooks = () => {
|
||||
triggers._unregisterAll();
|
||||
const config = Config.get(Parse.applicationId);
|
||||
config?.unregisterRateLimiters();
|
||||
};
|
||||
|
||||
ParseCloud.useMasterKey = () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import RedisCacheAdapter from './Adapters/Cache/RedisCacheAdapter';
|
||||
import LRUCacheAdapter from './Adapters/Cache/LRUCache.js';
|
||||
import * as TestUtils from './TestUtils';
|
||||
import * as SchemaMigrations from './SchemaMigrations/Migrations';
|
||||
import AuthAdapter from './Adapters/Auth/AuthAdapter';
|
||||
|
||||
import { useExternal } from './deprecated';
|
||||
import { getLogger } from './logger';
|
||||
@@ -43,4 +44,5 @@ export {
|
||||
ParseGraphQLServer,
|
||||
_ParseServer as ParseServer,
|
||||
SchemaMigrations,
|
||||
AuthAdapter,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,8 @@ import rateLimit from 'express-rate-limit';
|
||||
import { RateLimitOptions } from './Options/Definitions';
|
||||
import pathToRegexp from 'path-to-regexp';
|
||||
import ipRangeCheck from 'ip-range-check';
|
||||
import RedisStore from 'rate-limit-redis';
|
||||
import { createClient } from 'redis';
|
||||
|
||||
export const DEFAULT_ALLOWED_HEADERS =
|
||||
'X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, X-Parse-Request-Id, Content-Type, Pragma, Cache-Control';
|
||||
@@ -382,8 +384,13 @@ export function allowCrossDomain(appId) {
|
||||
if (config && config.allowHeaders) {
|
||||
allowHeaders += `, ${config.allowHeaders.join(', ')}`;
|
||||
}
|
||||
const allowOrigin = (config && config.allowOrigin) || '*';
|
||||
res.header('Access-Control-Allow-Origin', allowOrigin);
|
||||
|
||||
const baseOrigins =
|
||||
typeof config?.allowOrigin === 'string' ? [config.allowOrigin] : config?.allowOrigin ?? ['*'];
|
||||
const requestOrigin = req.headers.origin;
|
||||
const allowOrigins =
|
||||
requestOrigin && baseOrigins.includes(requestOrigin) ? requestOrigin : baseOrigins[0];
|
||||
res.header('Access-Control-Allow-Origin', allowOrigins);
|
||||
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
|
||||
res.header('Access-Control-Allow-Headers', allowHeaders);
|
||||
res.header('Access-Control-Expose-Headers', 'X-Parse-Job-Status-Id, X-Parse-Push-Status-Id');
|
||||
@@ -464,7 +471,7 @@ export function promiseEnforceMasterKeyAccess(request) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export const addRateLimit = (route, config) => {
|
||||
export const addRateLimit = (route, config, cloud) => {
|
||||
if (typeof config === 'string') {
|
||||
config = Config.get(config);
|
||||
}
|
||||
@@ -476,6 +483,35 @@ export const addRateLimit = (route, config) => {
|
||||
if (!config.rateLimits) {
|
||||
config.rateLimits = [];
|
||||
}
|
||||
const redisStore = {
|
||||
connectionPromise: Promise.resolve(),
|
||||
store: null,
|
||||
connected: false,
|
||||
};
|
||||
if (route.redisUrl) {
|
||||
const client = createClient({
|
||||
url: route.redisUrl,
|
||||
});
|
||||
redisStore.connectionPromise = async () => {
|
||||
if (redisStore.connected) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await client.connect();
|
||||
redisStore.connected = true;
|
||||
} catch (e) {
|
||||
const log = config?.loggerController || defaultLogger;
|
||||
log.error(`Could not connect to redisURL in rate limit: ${e}`);
|
||||
}
|
||||
};
|
||||
redisStore.connectionPromise();
|
||||
redisStore.store = new RedisStore({
|
||||
sendCommand: async (...args) => {
|
||||
await redisStore.connectionPromise();
|
||||
return client.sendCommand(args);
|
||||
},
|
||||
});
|
||||
}
|
||||
config.rateLimits.push({
|
||||
path: pathToRegexp(route.requestPath),
|
||||
handler: rateLimit({
|
||||
@@ -512,7 +548,9 @@ export const addRateLimit = (route, config) => {
|
||||
keyGenerator: request => {
|
||||
return request.config.ip;
|
||||
},
|
||||
store: redisStore.store,
|
||||
}),
|
||||
cloud,
|
||||
});
|
||||
Config.put(config);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user