diff --git a/.eslintrc.json b/.eslintrc.json index c04e2d3109..5995321633 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,8 +25,5 @@ "space-infix-ops": "error", "no-useless-escape": "off", "require-atomic-updates": "off" - }, - "globals": { - "Parse": true } } diff --git a/.github/workflows/ci-automated-check-environment.yml b/.github/workflows/ci-automated-check-environment.yml index ae83f879f1..0f08d2e47a 100644 --- a/.github/workflows/ci-automated-check-environment.yml +++ b/.github/workflows/ci-automated-check-environment.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout default branch - uses: actions/checkout@v4 + uses: actions/checkout@v2 - name: Setup Node uses: actions/setup-node@v2 with: node-version: 14 - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout default branch - uses: actions/checkout@v4 + uses: actions/checkout@v2 - name: Compose branch name for PR id: branch run: echo "::set-output name=name::ci-bump-environment" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ee28a7ee3..756e4e2419 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,14 @@ 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: 20.11.1 + NODE_VERSION: 19.3.0 PARSE_SERVER_TEST_TIMEOUT: 20000 jobs: check-code-analysis: @@ -21,29 +21,29 @@ jobs: strategy: fail-fast: false matrix: - language: ['javascript'] + language: [ 'javascript' ] steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - source-root: src - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - 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 check-ci: name: Node Engine Check timeout-minutes: 15 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.NODE_VERSION }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} @@ -54,37 +54,37 @@ jobs: - 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@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 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 check-definitions: - name: Check Definitions - timeout-minutes: 5 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 + name: Check Definitions + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.NODE_VERSION }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} @@ -95,48 +95,48 @@ 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@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 + 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 check-docker: name: Docker Build timeout-minutes: 15 - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v2 - name: Set up QEMU id: qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v1 - name: Build docker image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64, linux/arm64/v8 + platforms: linux/amd64 check-lock-file-version: name: NPM Lock File Version timeout-minutes: 5 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - name: Check NPM lock file version uses: mansona/npm-lockfile-version@v1 with: @@ -147,33 +147,37 @@ jobs: include: - name: MongoDB 4.2, ReplicaSet MONGODB_VERSION: 4.2.19 - MONGODB_TOPOLOGY: replset - NODE_VERSION: 20.11.1 + MONGODB_TOPOLOGY: replicaset + NODE_VERSION: 19.3.0 - name: MongoDB 4.4, ReplicaSet MONGODB_VERSION: 4.4.13 - MONGODB_TOPOLOGY: replset - NODE_VERSION: 20.11.1 + MONGODB_TOPOLOGY: replicaset + NODE_VERSION: 19.3.0 - name: MongoDB 5, ReplicaSet MONGODB_VERSION: 5.3.2 - MONGODB_TOPOLOGY: replset - NODE_VERSION: 20.11.1 + MONGODB_TOPOLOGY: replicaset + NODE_VERSION: 19.3.0 - name: MongoDB 6, ReplicaSet MONGODB_VERSION: 6.0.2 - MONGODB_TOPOLOGY: replset - NODE_VERSION: 20.11.1 - - name: MongoDB 7, ReplicaSet - MONGODB_VERSION: 7.0.1 - MONGODB_TOPOLOGY: replset - NODE_VERSION: 20.11.1 + MONGODB_TOPOLOGY: replicaset + NODE_VERSION: 19.3.0 - name: Redis Cache PARSE_SERVER_TEST_CACHE: redis MONGODB_VERSION: 4.4.13 MONGODB_TOPOLOGY: standalone - NODE_VERSION: 20.11.1 + NODE_VERSION: 19.3.0 + - name: Node 14 + MONGODB_VERSION: 4.4.13 + MONGODB_TOPOLOGY: standalone + NODE_VERSION: 14.21.1 + - name: Node 16 + MONGODB_VERSION: 4.4.13 + MONGODB_TOPOLOGY: standalone + NODE_VERSION: 16.18.1 - name: Node 18 MONGODB_VERSION: 4.4.13 MONGODB_TOPOLOGY: standalone - NODE_VERSION: 18.19.1 + NODE_VERSION: 18.12.1 fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 @@ -182,7 +186,7 @@ jobs: redis: image: redis ports: - - 6379:6379 + - 6379:6379 env: MONGODB_VERSION: ${{ matrix.MONGODB_VERSION }} MONGODB_TOPOLOGY: ${{ matrix.MONGODB_TOPOLOGY }} @@ -192,13 +196,16 @@ jobs: steps: - name: Fix usage of insecure GitHub protocol run: sudo git config --system url."https://github".insteadOf "git://github" - - uses: actions/checkout@v4 + - 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 - name: Use Node.js ${{ matrix.NODE_VERSION }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.NODE_VERSION }} - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} @@ -215,27 +222,30 @@ jobs: strategy: matrix: include: - - name: PostgreSQL 13, PostGIS 3.1 - POSTGRES_IMAGE: postgis/postgis:13-3.1 - NODE_VERSION: 20.11.1 - - name: PostgreSQL 13, PostGIS 3.2 - POSTGRES_IMAGE: postgis/postgis:13-3.2 - NODE_VERSION: 20.11.1 + - 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: 20.11.1 - - name: PostgreSQL 13, PostGIS 3.4 - POSTGRES_IMAGE: postgis/postgis:13-3.4 - NODE_VERSION: 20.11.1 - - name: PostgreSQL 14, PostGIS 3.4 - POSTGRES_IMAGE: postgis/postgis:14-3.4 - NODE_VERSION: 20.11.1 - - name: PostgreSQL 15, PostGIS 3.4 - POSTGRES_IMAGE: postgis/postgis:15-3.4 - NODE_VERSION: 20.11.1 - - name: PostgreSQL 16, PostGIS 3.4 - POSTGRES_IMAGE: postgis/postgis:15-3.4 - NODE_VERSION: 20.11.1 + 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 fail-fast: false name: ${{ matrix.name }} timeout-minutes: 15 @@ -261,13 +271,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@v4 + - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.NODE_VERSION }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.NODE_VERSION }} - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/release-automated.yml b/.github/workflows/release-automated.yml index 1f517abf79..271d4abca3 100644 --- a/.github/workflows/release-automated.yml +++ b/.github/workflows/release-automated.yml @@ -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@v4 + - uses: actions/checkout@v2 with: persist-credentials: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v2 with: - node-version: 18.19.1 + node-version: 18.1.0 registry-url: https://registry.npmjs.org/ - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -42,7 +42,7 @@ jobs: env: REGISTRY: docker.io IMAGE_NAME: parseplatform/parse-server - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest permissions: contents: read packages: write @@ -51,23 +51,23 @@ jobs: id: branch run: echo "::set-output name=branch_name::${GITHUB_REF#refs/*/}" - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v2 with: ref: ${{ needs.release.outputs.current_tag }} - name: Set up QEMU id: qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v1 - name: Log into Docker Hub if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v3 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} flavor: | @@ -75,7 +75,7 @@ jobs: tags: | type=semver,pattern={{version}},value=${{ needs.release.outputs.current_tag }} - name: Build and push Docker image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64/v8 @@ -89,13 +89,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - name: Use Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v1 with: - node-version: 18.19.1 + node-version: 18.1.0 - name: Cache Node.js modules - uses: actions/cache@v4 + uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} @@ -112,4 +112,4 @@ jobs: uses: peaceiris/actions-gh-pages@v3.7.3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs + publish_dir: ./docs \ No newline at end of file diff --git a/.github/workflows/release-manual-docker.yml b/.github/workflows/release-manual-docker.yml index 98d5ef83dd..1d19189c3a 100644 --- a/.github/workflows/release-manual-docker.yml +++ b/.github/workflows/release-manual-docker.yml @@ -14,7 +14,7 @@ env: IMAGE_NAME: parseplatform/parse-server jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest permissions: contents: read packages: write @@ -23,23 +23,23 @@ jobs: id: branch run: echo "::set-output name=branch_name::${GITHUB_REF#refs/*/}" - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.ref }} - name: Set up QEMU id: qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v1 - name: Log into Docker Hub if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v3 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} flavor: | @@ -48,7 +48,7 @@ jobs: type=semver,enable=true,pattern={{version}},value=${{ github.event.inputs.ref }} type=raw,enable=${{ github.event.inputs.ref == '' }},value=latest - name: Build and push Docker image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64/v8 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 270b66e385..3d70f6aa63 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -242,11 +242,7 @@ Once you have babel running in watch mode, you can start making changes to parse If your pull request introduces a change that may affect the storage or retrieval of objects, you may want to make sure it plays nice with Postgres. -* 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 - ``` +* 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). * 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: @@ -268,10 +264,10 @@ If your pull request introduces a change that may affect the storage or retrieva #### Postgres with Docker -[PostGIS images (select one with v2.2 or higher) on docker 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: +[PostGIS images (select one with v2.2 or higher) on docker dashboard](https://hub.docker.com/r/postgis/postgis) is based off of the official [postgres](https://registry.hub.docker.com/_/postgres/) image and will work out-of-the-box (as long as you create a user with the necessary extensions for each of your Parse databases; see below). To launch the compatible Postgres instance, copy and paste the following line into your shell: ``` -docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:16-3.4-alpine && sleep 20 && docker exec -it parse-postgres psql -U postgres -c 'CREATE DATABASE parse_server_postgres_adapter_test_database;' && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION pgcrypto; CREATE EXTENSION postgis;' -d parse_server_postgres_adapter_test_database && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis_topology;' -d parse_server_postgres_adapter_test_database +docker run -d --name parse-postgres -p 5432:5432 -e POSTGRES_PASSWORD=password --rm postgis/postgis:13-3.2-alpine && sleep 20 && docker exec -it parse-postgres psql -U postgres -c 'CREATE DATABASE parse_server_postgres_adapter_test_database;' && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION pgcrypto; CREATE EXTENSION postgis;' -d parse_server_postgres_adapter_test_database && docker exec -it parse-postgres psql -U postgres -c 'CREATE EXTENSION postgis_topology;' -d parse_server_postgres_adapter_test_database ``` To stop the Postgres instance: @@ -279,7 +275,7 @@ To stop the Postgres instance: docker stop parse-postgres ``` -You can also use the [postgis/postgis:16-3.4-alpine](https://hub.docker.com/r/postgis/postgis) image in a Dockerfile and copy this [script](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) to the image by adding the following lines: +You can also use the [postgis/postgis:13-3.2-alpine](https://hub.docker.com/r/postgis/postgis) image in a Dockerfile and copy this [script](https://github.com/parse-community/parse-server/blob/master/scripts/before_script_postgres.sh) to the image by adding the following lines: ``` #Install additional scripts. These are run in abc order during initial start diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md index 73841840f9..56359c937e 100644 --- a/DEPRECATIONS.md +++ b/DEPRECATIONS.md @@ -9,11 +9,10 @@ The following is a list of deprecations, according to the [Deprecation Policy](h | 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) | removed | - | -| DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - | -| DEPPS8 | Login with expired 3rd party authentication token defaults to `false` | [#7079](https://github.com/parse-community/parse-server/pull/7079) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - | -| DEPPS9 | Rename LiveQuery `fields` option to `keys` | [#8389](https://github.com/parse-community/parse-server/issues/8389) | 6.0.0 (2023) | 7.0.0 (2024) | removed | - | -| DEPPS10 | Config option `encodeParseObjectInCloudFunction` defaults to `true` | [#8634](https://github.com/parse-community/parse-server/issues/8634) | 6.2.0 (2023) | 8.0.0 (2025) | deprecated | - | +| 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 | - | [i_deprecation]: ## "The version and date of the deprecation." [i_removal]: ## "The version and date of the planned removal." diff --git a/Dockerfile b/Dockerfile index 3cb4e2530c..413a9bd279 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ############################################################ # Build stage ############################################################ -FROM node:18-alpine AS build +FROM node:lts-alpine AS build RUN apk --no-cache add git WORKDIR /tmp @@ -24,7 +24,7 @@ RUN npm ci --omit=dev --ignore-scripts \ ############################################################ # Release stage ############################################################ -FROM node:18-alpine AS release +FROM node:lts-alpine AS release VOLUME /parse-server/cloud /parse-server/config diff --git a/README.md b/README.md index fa99c2f9bc..0288d5f4ba 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ [![Coverage](https://img.shields.io/codecov/c/github/parse-community/parse-server/alpha.svg)](https://codecov.io/github/parse-community/parse-server?branch=alpha) [![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/parse-dashboard/releases) -[![Node Version](https://img.shields.io/badge/nodejs-18,_20-green.svg?logo=node.js&style=flat)](https://nodejs.org) +[![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-13,_14,_15,_16-green.svg?logo=postgresql&style=flat)](https://www.postgresql.org) +[![Postgres Version](https://img.shields.io/badge/postgresql-11,_12,_13,_14,_15-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) @@ -129,21 +129,22 @@ Parse Server is continuously tested with the most recent releases of Node.js to | Version | Latest Version | End-of-Life | Compatible | |------------|----------------|-------------|------------| -| Node.js 18 | 18.19.1 | April 2025 | ✅ Yes | -| Node.js 20 | 20.11.1 | April 2026 | ✅ Yes | +| 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 | #### 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. | 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 | -| MongoDB 7 | 7.0.1 | TDB | ✅ Yes | +|-------------|----------------|---------------|------------| +| 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 | #### PostgreSQL @@ -151,10 +152,11 @@ Parse Server is continuously tested with the most recent releases of PostgreSQL | Version | PostGIS Version | End-of-Life | Parse Server Support | Compatible | |-------------|--------------------|---------------|----------------------|------------| -| Postgres 13 | 3.1, 3.2, 3.3, 3.4 | November 2025 | <= 6.x (2023) | ✅ Yes | -| Postgres 14 | 3.4 | November 2026 | <= 7.x (2024) | ✅ Yes | -| Postgres 15 | 3.4 | November 2027 | <= 8.x (2025) | ✅ Yes | -| Postgres 16 | 3.4 | November 2028 | <= 9.x (2026) | ✅ Yes | +| 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 | ### Locally @@ -356,14 +358,12 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo ## Access Scopes -| Scope | Internal data | Read-only data (1) | Custom data | Restricted by CLP, ACL | Key | -|----------------|---------------|-------------------------------|-------------|------------------------|---------------------| -| Internal | r/w | r/w | r/w | no | `maintenanceKey` | -| Master | -/- | r/- | r/w | no | `masterKey` | -| ReadOnlyMaster | -/- | r/- | r/- | no | `readOnlyMasterKey` | -| Session | -/- | r/- | r/w | yes | `sessionToken` | - -(1) `Parse.Object.createdAt`, `Parse.Object.updatedAt`. +| Scope | Internal data | Custom data | Restricted by CLP, ACL | Key | +|----------------|---------------|-------------|------------------------|---------------------| +| Internal | r/w | r/w | no | `maintenanceKey` | +| Master | -/- | r/w | no | `masterKey` | +| ReadOnlyMaster | -/- | r/- | no | `readOnlyMasterKey` | +| Session | -/- | r/w | yes | `sessionToken` | ## Email Verification and Password Reset diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index f24d770c92..b9b1925b78 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,351 +1,3 @@ -# [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)) - -# [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..enabled: true` ([0cf58eb](0cf58eb)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [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)) - -# [6.5.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.5.0-alpha.1...6.5.0-alpha.2) (2023-11-19) - - -### Performance Improvements - -* Improved IP validation performance for `masterKeyIPs`, `maintenanceKeyIPs` ([#8510](https://github.com/parse-community/parse-server/issues/8510)) ([b87daba](https://github.com/parse-community/parse-server/commit/b87daba0671a1b0b7b8d63bc671d665c91a04522)) - -# [6.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-alpha.1) (2023-11-18) - - -### Bug Fixes - -* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) -* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) -* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) -* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) - -### Features - -* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) -* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) -* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) -* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) -* Upgrade Parse Server Push Adapter to 5.0.2 ([#8813](https://github.com/parse-community/parse-server/issues/8813)) ([6ef1986](https://github.com/parse-community/parse-server/commit/6ef1986c03a1d84b7e11c05851e5bf9688d88740)) - -# [6.4.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.7...6.4.0-alpha.8) (2023-11-13) - - -### Features - -* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) - -# [6.4.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.6...6.4.0-alpha.7) (2023-10-25) - - -### Features - -* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) - -# [6.4.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.5...6.4.0-alpha.6) (2023-10-18) - - -### Bug Fixes - -* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) - -# [6.4.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.4...6.4.0-alpha.5) (2023-10-14) - - -### Bug Fixes - -* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) - -# [6.4.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.3...6.4.0-alpha.4) (2023-09-29) - - -### Features - -* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) - -# [6.4.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.2...6.4.0-alpha.3) (2023-09-23) - - -### Bug Fixes - -* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) - -# [6.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.4.0-alpha.1...6.4.0-alpha.2) (2023-09-22) - - -### Bug Fixes - -* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) - -# [6.4.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-alpha.1) (2023-09-20) - -### Features - -* 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)) - -# [6.3.0-alpha.9](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.8...6.3.0-alpha.9) (2023-09-13) - - -### Performance Improvements - -* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) - -# [6.3.0-alpha.8](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.7...6.3.0-alpha.8) (2023-08-30) - - -### Bug Fixes - -* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) - -# [6.3.0-alpha.7](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.6...6.3.0-alpha.7) (2023-08-18) - - -### Bug Fixes - -* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) - -# [6.3.0-alpha.6](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.5...6.3.0-alpha.6) (2023-07-17) - - -### Bug Fixes - -* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) - -# [6.3.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.4...6.3.0-alpha.5) (2023-07-05) - - -### Features - -* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) - -# [6.3.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.3...6.3.0-alpha.4) (2023-07-04) - - -### Bug Fixes - -* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) - -# [6.3.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.2...6.3.0-alpha.3) (2023-06-23) - - -### Features - -* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) - -# [6.3.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.3.0-alpha.1...6.3.0-alpha.2) (2023-06-20) - - -### Features - -* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) - -# [6.3.0-alpha.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.3.0-alpha.1) (2023-06-18) - - -### Bug Fixes - -* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804)) -* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394)) -* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4)) -* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b)) -* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e)) -* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae)) - -### Features - -* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029)) -* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab)) -* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d)) -* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e)) -* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e)) -* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761)) - -### Reverts - -* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff)) - # [6.1.0-alpha.20](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.19...6.1.0-alpha.20) (2023-06-09) diff --git a/changelogs/CHANGELOG_beta.md b/changelogs/CHANGELOG_beta.md index dd80a35e3e..289b86d780 100644 --- a/changelogs/CHANGELOG_beta.md +++ b/changelogs/CHANGELOG_beta.md @@ -1,40 +1,3 @@ -# [6.5.0-beta.1](https://github.com/parse-community/parse-server/compare/6.4.0...6.5.0-beta.1) (2023-11-16) - - -### Bug Fixes - -* Context not passed to Cloud Code Trigger `beforeFind` when using `Parse.Query.include` ([#8765](https://github.com/parse-community/parse-server/issues/8765)) ([7d32d89](https://github.com/parse-community/parse-server/commit/7d32d8934f3ae7af7a7d8b9cc6a829c7d73973d3)) -* Parse Server option `fileUpload.fileExtensions` fails to determine file extension if filename contains multiple dots ([#8754](https://github.com/parse-community/parse-server/issues/8754)) ([3d6d50e](https://github.com/parse-community/parse-server/commit/3d6d50e0afff18b95fb906914e2cebd3839b517a)) -* Security bump @babel/traverse from 7.20.5 to 7.23.2 ([#8777](https://github.com/parse-community/parse-server/issues/8777)) ([2d6b3d1](https://github.com/parse-community/parse-server/commit/2d6b3d18499179e99be116f25c0850d3f449509c)) -* Security upgrade graphql from 16.6.0 to 16.8.1 ([#8758](https://github.com/parse-community/parse-server/issues/8758)) ([71dfd8a](https://github.com/parse-community/parse-server/commit/71dfd8a7ece8c0dd1a66d03bb9420cfd39f4f9b1)) - -### Features - -* Add `$setOnInsert` operator to `Parse.Server.database.update` ([#8791](https://github.com/parse-community/parse-server/issues/8791)) ([f630a45](https://github.com/parse-community/parse-server/commit/f630a45aa5e87bc73a81fded061400c199b71a29)) -* Add compatibility for MongoDB Atlas Serverless and AWS Amazon DocumentDB with collation options `enableCollationCaseComparison`, `transformEmailToLowercase`, `transformUsernameToLowercase` ([#8805](https://github.com/parse-community/parse-server/issues/8805)) ([09fbeeb](https://github.com/parse-community/parse-server/commit/09fbeebba8870e7cf371fb84371a254c7b368620)) -* Add context to Cloud Code Triggers `beforeLogin` and `afterLogin` ([#8724](https://github.com/parse-community/parse-server/issues/8724)) ([a9c34ef](https://github.com/parse-community/parse-server/commit/a9c34ef1e2c78a42fb8b5fa8d569b7677c74919d)) -* Allow setting `createdAt` and `updatedAt` during `Parse.Object` creation with maintenance key ([#8696](https://github.com/parse-community/parse-server/issues/8696)) ([77bbfb3](https://github.com/parse-community/parse-server/commit/77bbfb3f186f5651c33ba152f04cff95128eaf2d)) - -# [6.4.0-beta.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.4.0-beta.1) (2023-09-16) - - -### Bug Fixes - -* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) -* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) -* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) -* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) - -### Features - -* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) -* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) -* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) - -### Performance Improvements - -* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) - # [6.3.0-beta.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.3.0-beta.1) (2023-06-10) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index eaf5301ccc..4cd0131cdb 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,69 +1,3 @@ -# [6.4.0](https://github.com/parse-community/parse-server/compare/6.3.1...6.4.0) (2023-11-16) - - -### Bug Fixes - -* Parse Server option `fileUpload.fileExtensions` does not work with an array of extensions ([#8688](https://github.com/parse-community/parse-server/issues/8688)) ([6a4a00c](https://github.com/parse-community/parse-server/commit/6a4a00ca7af1163ea74b047b85cd6817366b824b)) -* Redis 4 does not reconnect after unhandled error ([#8706](https://github.com/parse-community/parse-server/issues/8706)) ([2b3d4e5](https://github.com/parse-community/parse-server/commit/2b3d4e5d3c85cd142f85af68dec51a8523548d49)) -* Remove config logging when launching Parse Server via CLI ([#8710](https://github.com/parse-community/parse-server/issues/8710)) ([ae68f0c](https://github.com/parse-community/parse-server/commit/ae68f0c31b741eeb83379c905c7ddfaa124436ec)) -* Server does not start via CLI when `auth` option is set ([#8666](https://github.com/parse-community/parse-server/issues/8666)) ([4e2000b](https://github.com/parse-community/parse-server/commit/4e2000bc563324389584ace3c090a5c1a7796a64)) - -### Features - -* Add conditional email verification via dynamic Parse Server options `verifyUserEmails`, `sendUserEmailVerification` that now accept functions ([#8425](https://github.com/parse-community/parse-server/issues/8425)) ([44acd6d](https://github.com/parse-community/parse-server/commit/44acd6d9ed157ad4842200c9d01f9c77a05fec3a)) -* Add property `Parse.Server.version` to determine current version of Parse Server in Cloud Code ([#8670](https://github.com/parse-community/parse-server/issues/8670)) ([a9d376b](https://github.com/parse-community/parse-server/commit/a9d376b61f5b07806eafbda91c4e36c322f09298)) -* Add TOTP authentication adapter ([#8457](https://github.com/parse-community/parse-server/issues/8457)) ([cc079a4](https://github.com/parse-community/parse-server/commit/cc079a40f6849a0e9bc6fdc811e8649ecb67b589)) - -### Performance Improvements - -* Improve performance of recursive pointer iterations ([#8741](https://github.com/parse-community/parse-server/issues/8741)) ([45a3ed0](https://github.com/parse-community/parse-server/commit/45a3ed0fcf2c0170607505a1550fb15896e705fd)) - -## [6.3.1](https://github.com/parse-community/parse-server/compare/6.3.0...6.3.1) (2023-10-20) - - -### Bug Fixes - -* Server crash when uploading file without extension; fixes security vulnerability [GHSA-792q-q67h-w579](https://github.com/parse-community/parse-server/security/advisories/GHSA-792q-q67h-w579) ([#8781](https://github.com/parse-community/parse-server/issues/8781)) ([fd86278](https://github.com/parse-community/parse-server/commit/fd86278919556d3682e7e2c856dfccd5beffbfc0)) - -# [6.3.0](https://github.com/parse-community/parse-server/compare/6.2.2...6.3.0) (2023-09-16) - - -### Bug Fixes - -* Cloud Code Trigger `afterSave` executes even if not set ([#8520](https://github.com/parse-community/parse-server/issues/8520)) ([afd0515](https://github.com/parse-community/parse-server/commit/afd0515e207bd947840579d3f245980dffa6f804)) -* GridFS file storage doesn't work with certain `enableSchemaHooks` settings ([#8467](https://github.com/parse-community/parse-server/issues/8467)) ([d4cda4b](https://github.com/parse-community/parse-server/commit/d4cda4b26c9bde8c812549b8780bea1cfabdb394)) -* Inaccurate table total row count for PostgreSQL ([#8511](https://github.com/parse-community/parse-server/issues/8511)) ([0823a02](https://github.com/parse-community/parse-server/commit/0823a02fbf80bc88dc403bc47e9f5c6597ea78b4)) -* LiveQuery server is not shut down properly when `handleShutdown` is called ([#8491](https://github.com/parse-community/parse-server/issues/8491)) ([967700b](https://github.com/parse-community/parse-server/commit/967700bdbc94c74f75ba84d2b3f4b9f3fd2dca0b)) -* Rate limit feature is incompatible with Node 14 ([#8578](https://github.com/parse-community/parse-server/issues/8578)) ([f911f2c](https://github.com/parse-community/parse-server/commit/f911f2cd3a8c45cd326272dcd681532764a3761e)) -* Unnecessary log entries by `extendSessionOnUse` ([#8562](https://github.com/parse-community/parse-server/issues/8562)) ([fd6a007](https://github.com/parse-community/parse-server/commit/fd6a0077f2e5cf83d65e52172ae5a950ab0f1eae)) - -### Features - -* `extendSessionOnUse` to automatically renew Parse Sessions ([#8505](https://github.com/parse-community/parse-server/issues/8505)) ([6f885d3](https://github.com/parse-community/parse-server/commit/6f885d36b94902fdfea873fc554dee83589e6029)) -* Add new Parse Server option `preventSignupWithUnverifiedEmail` to prevent returning a user without session token on sign-up with unverified email address ([#8451](https://github.com/parse-community/parse-server/issues/8451)) ([82da308](https://github.com/parse-community/parse-server/commit/82da30842a55980aa90cb7680fbf6db37ee16dab)) -* Add option to change the log level of logs emitted by Cloud Functions ([#8530](https://github.com/parse-community/parse-server/issues/8530)) ([2caea31](https://github.com/parse-community/parse-server/commit/2caea310be412d82b04a85716bc769ccc410316d)) -* Add support for `$eq` query constraint in LiveQuery ([#8614](https://github.com/parse-community/parse-server/issues/8614)) ([656d673](https://github.com/parse-community/parse-server/commit/656d673cf5dea354e4f2b3d4dc2b29a41d311b3e)) -* Add zones for rate limiting by `ip`, `user`, `session`, `global` ([#8508](https://github.com/parse-community/parse-server/issues/8508)) ([03fba97](https://github.com/parse-community/parse-server/commit/03fba97e0549bfcaeee9f2fa4c9905dbcc91840e)) -* Allow `Parse.Object` pointers in Cloud Code arguments ([#8490](https://github.com/parse-community/parse-server/issues/8490)) ([28aeda3](https://github.com/parse-community/parse-server/commit/28aeda3f160efcbbcf85a85484a8d26567fa9761)) - -### Reverts - -* fix: Inaccurate table total row count for PostgreSQL ([6722110](https://github.com/parse-community/parse-server/commit/6722110f203bc5fdcaa68cdf091cf9e7b48d1cff)) - -## [6.2.2](https://github.com/parse-community/parse-server/compare/6.2.1...6.2.2) (2023-09-04) - - -### Bug Fixes - -* Parse Pointer allows to access internal Parse Server classes and circumvent `beforeFind` query trigger; fixes security vulnerability [GHSA-fcv6-fg5r-jm9q](https://github.com/parse-community/parse-server/security/advisories/GHSA-fcv6-fg5r-jm9q) ([be4c7e2](https://github.com/parse-community/parse-server/commit/be4c7e23c63a2fb690685665cebed0de26be05c5)) - -## [6.2.1](https://github.com/parse-community/parse-server/compare/6.2.0...6.2.1) (2023-06-28) - - -### Bug Fixes - -* Remote code execution via MongoDB BSON parser through prototype pollution; fixes security vulnerability [GHSA-462x-c3jw-7vr6](https://github.com/parse-community/parse-server/security/advisories/GHSA-462x-c3jw-7vr6) ([#8674](https://github.com/parse-community/parse-server/issues/8674)) ([3dd99dd](https://github.com/parse-community/parse-server/commit/3dd99dd80e27e5e1d99b42844180546d90c7aa90)) - # [6.2.0](https://github.com/parse-community/parse-server/compare/6.1.0...6.2.0) (2023-05-20) diff --git a/jsdoc-conf.json b/jsdoc-conf.json index efbaa0a37c..4a1e5de846 100644 --- a/jsdoc-conf.json +++ b/jsdoc-conf.json @@ -29,7 +29,7 @@ "template": "./node_modules/clean-jsdoc-theme", "theme_opts": { "default_theme": "dark", - "title": "", + "title": "Parse Server", "create_style": "header, .sidebar-section-title, .sidebar-title { color: #139cee !important } .logo { margin-left : 40px; margin-right: 40px }" } }, diff --git a/package-lock.json b/package-lock.json index 57ea967d43..a617dd7c3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-server", - "version": "7.0.0-alpha.19", + "version": "6.3.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "parse-server", - "version": "7.0.0-alpha.19", + "version": "6.3.0-beta.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -15,8 +15,8 @@ "@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.0.2", + "@parse/fs-files-adapter": "1.2.2", + "@parse/push-adapter": "4.1.3", "bcryptjs": "2.4.3", "body-parser": "1.20.2", "commander": "10.0.1", @@ -24,35 +24,35 @@ "deepcopy": "2.1.0", "express": "4.18.2", "express-rate-limit": "6.7.0", - "follow-redirects": "1.15.4", - "graphql": "16.8.1", + "follow-redirects": "1.15.2", + "graphql": "16.6.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.10.0", "graphql-tag": "2.12.6", "intersect": "1.0.1", + "ip-range-check": "0.2.0", "jsonwebtoken": "9.0.0", - "jwks-rsa": "^3.1.0", - "ldapjs": "2.3.3", + "jwks-rsa": "2.1.5", + "ldapjs": "3.0.2", "lodash": "4.17.21", - "lru-cache": "10.1.0", + "lru-cache": "9.1.1", "mime": "3.0.0", - "mongodb": "5.9.0", + "mongodb": "4.10.0", "mustache": "4.2.0", - "otpauth": "9.2.1", "parse": "4.1.0", "path-to-regexp": "6.2.1", "pg-monitor": "2.0.0", - "pg-promise": "11.5.4", + "pg-promise": "11.5.0", "pluralize": "8.0.0", "rate-limit-redis": "3.0.2", - "redis": "4.6.11", - "semver": "7.5.2", + "redis": "4.6.6", + "semver": "7.5.1", "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", "uuid": "9.0.0", "winston": "3.8.2", "winston-daily-rotate-file": "4.7.1", - "ws": "8.15.1" + "ws": "8.13.0" }, "bin": { "parse-server": "bin/parse-server" @@ -74,6 +74,7 @@ "@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", "deep-diff": "1.0.2", @@ -91,7 +92,7 @@ "madge": "5.0.1", "mock-files-adapter": "file:spec/dependencies/mock-files-adapter", "mock-mail-adapter": "file:spec/dependencies/mock-mail-adapter", - "mongodb-runner": "5.4.4", + "mongodb-runner": "4.8.1", "mongodb-version-list": "1.0.0", "node-abort-controller": "3.0.1", "node-fetch": "3.2.10", @@ -101,7 +102,7 @@ "yaml": "1.10.0" }, "engines": { - "node": ">=18.0.0 <21" + "node": ">=14.21.0 <17 || >=18 <19" }, "funding": { "type": "opencollective", @@ -225,12 +226,11 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -324,13 +324,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -376,9 +375,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "engines": { "node": ">=6.9.0" } @@ -396,23 +395,23 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -520,28 +519,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "engines": { "node": ">=6.9.0" } @@ -583,12 +582,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, "engines": { @@ -596,9 +595,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "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" }, @@ -1797,31 +1796,31 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.5", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1830,12 +1829,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2326,70 +2325,83 @@ "node": ">=v12.0.0" } }, - "node_modules/@mongodb-js/mongodb-downloader": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-downloader/-/mongodb-downloader-0.2.8.tgz", - "integrity": "sha512-y+mgw9QspvgTLRNHZJRS+DUTPk45RWpvYD1MaGDWhZ4ajffvxGqanY+Z4R6z01n+tIRmQvpShzF6zk+2Pr9d6w==", - "dev": true, + "node_modules/@ldapjs/asn1": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-2.0.0.tgz", + "integrity": "sha512-G9+DkEOirNgdPmD0I8nu57ygQJKOOgFEMKknEuQvIHbGLwP3ny1mY+OTUYLCbCaGJP4sox5eYgBJRuSUpnAddA==" + }, + "node_modules/@ldapjs/attribute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/attribute/-/attribute-1.0.0.tgz", + "integrity": "sha512-ptMl2d/5xJ0q+RgmnqOi3Zgwk/TMJYG7dYMC0Keko+yZU6n+oFM59MjQOUht5pxJeS4FWrImhu/LebX24vJNRQ==", "dependencies": { - "debug": "^4.3.4", - "decompress": "^4.2.1", - "mongodb-download-url": "^1.3.0", - "node-fetch": "^2.6.11", - "tar": "^6.1.15" + "@ldapjs/asn1": "2.0.0", + "@ldapjs/protocol": "^1.2.1", + "process-warning": "^2.1.0" } }, - "node_modules/@mongodb-js/mongodb-downloader/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, + "node_modules/@ldapjs/change": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/change/-/change-1.0.0.tgz", + "integrity": "sha512-EOQNFH1RIku3M1s0OAJOzGfAohuFYXFY4s73wOhRm4KFGhmQQ7MChOh2YtYu9Kwgvuq1B0xKciXVzHCGkB5V+Q==", "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "@ldapjs/asn1": "2.0.0", + "@ldapjs/attribute": "1.0.0" } }, - "node_modules/@mongodb-js/mongodb-downloader/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "node_modules/@ldapjs/controls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/controls/-/controls-2.0.0.tgz", + "integrity": "sha512-NpFmdIc2q83tYRGR2a3NDulKgU1e4YOgqjQmmMezCoN4Xz0tju4yB4eibQNC+Zg8YRW06KPwFPKbebDaCqFF0w==", + "dependencies": { + "@ldapjs/asn1": "^1.2.0", + "@ldapjs/protocol": "^1.2.1" + } }, - "node_modules/@mongodb-js/mongodb-downloader/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "node_modules/@ldapjs/controls/node_modules/@ldapjs/asn1": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-1.2.0.tgz", + "integrity": "sha512-KX/qQJ2xxzvO2/WOvr1UdQ+8P5dVvuOLk/C9b1bIkXxZss8BaR28njXdPgFCpj5aHaf1t8PmuVnea+N9YG9YMw==" }, - "node_modules/@mongodb-js/mongodb-downloader/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, + "node_modules/@ldapjs/dn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/dn/-/dn-1.0.0.tgz", + "integrity": "sha512-qPsJDC5dQU2TSkA/IpswvPEg9MU6TIjjq0UOCHtuUeD3eWihTUjHuu/dith4NFRKjBvgFnqRQvo+t0YC+3z0Rw==", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "@ldapjs/asn1": "2.0.0", + "process-warning": "^2.1.0" } }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", - "optional": true, + "node_modules/@ldapjs/filter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/filter/-/filter-2.0.0.tgz", + "integrity": "sha512-7hMv5DNlHJk4qoGzCFGbbSV0vgvn2A7hZ4mt15557xDhw+BXjhryBvs8ANTHUpyaWvESbU+oNOsbBobNLZ45Nw==", "dependencies": { - "sparse-bitfield": "^3.0.3" + "@ldapjs/asn1": "2.0.0", + "@ldapjs/protocol": "^1.2.1", + "process-warning": "^2.1.0" + } + }, + "node_modules/@ldapjs/messages": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@ldapjs/messages/-/messages-1.0.2.tgz", + "integrity": "sha512-aVYyqTDsIfnUt2Qr2syJi99M39h4ll9soggOtUjsf4Sv1xVQ/M5VY11T0h69S2fQ4NnaYi9iXd440LVU4MCCKQ==", + "dependencies": { + "@ldapjs/asn1": "2.0.0", + "@ldapjs/attribute": "1.0.0", + "@ldapjs/change": "1.0.0", + "@ldapjs/controls": "2.0.0", + "@ldapjs/dn": "1.0.0", + "@ldapjs/filter": "2.0.0", + "@ldapjs/protocol": "1.2.1", + "process-warning": "^2.1.0" } }, + "node_modules/@ldapjs/protocol": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ldapjs/protocol/-/protocol-1.2.1.tgz", + "integrity": "sha512-O89xFDLW2gBoZWNXuXpBSM32/KealKCTb3JGtJdtUQc7RjAk8XzrRgyz02cPAwGKwKPxy0ivuC7UP9bmN87egQ==" + }, "node_modules/@napi-rs/triples": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz", @@ -2781,23 +2793,31 @@ "@octokit/openapi-types": "^12.11.0" } }, + "node_modules/@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@parse/fs-files-adapter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-2.0.1.tgz", - "integrity": "sha512-9DY0T9lK73Ysw+wxxsBt9rpxWxJpMlHl/fTW175XSajusW0ZP5jERI3BTKeclV28eVmSU690EO2vnwCURsPZ7g==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.2.tgz", + "integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g==" }, "node_modules/@parse/node-apn": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-6.0.1.tgz", - "integrity": "sha512-QQxqEN/zbtEkSgj41oX/tQUavML+G+JHeQi2YVlgZlponnwIxA3fb5tEbXPm+fdR6rL1pi2/z2PcOwINOyx2eA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz", + "integrity": "sha512-Bwhmbm895lEIF2772PJ8dSvBjrtOG9/q/TDMxmX40IgZxQFoXS73+JUIKTq3CA7SUB/Szu5roJINQ0L2U/1MJw==", "dependencies": { "debug": "4.3.3", - "jsonwebtoken": "9.0.0", - "node-forge": "1.3.1", + "jsonwebtoken": "8.5.1", + "node-forge": "1.3.0", "verror": "1.10.1" }, "engines": { - "node": ">= 14" + "node": ">= 12" } }, "node_modules/@parse/node-apn/node_modules/debug": { @@ -2816,6 +2836,35 @@ } } }, + "node_modules/@parse/node-apn/node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/@parse/node-apn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/@parse/node-gcm": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@parse/node-gcm/-/node-gcm-1.0.2.tgz", @@ -2838,48 +2887,83 @@ } }, "node_modules/@parse/push-adapter": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-5.0.2.tgz", - "integrity": "sha512-0nVBGj8p8cYGjoMdkVAlsa/UlB1Z4W6Ch7MEVcEfnyCmJBw6bvHwB1VVWoclcRqi3phsu3SizR5zVvB/Cx8I/g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-4.1.3.tgz", + "integrity": "sha512-Oy53ag7DpUva5dUWwP6tNEsrxv2xU9QIk+rb84q1DIm1qVgo2yl4oXcZ3FPG2Ks/NYURbv4w+z9oaSgVfyBRfQ==", "dependencies": { - "@parse/node-apn": "6.0.1", + "@parse/node-apn": "5.1.3", "@parse/node-gcm": "1.0.2", "npmlog": "4.1.2", - "parse": "4.2.0" + "parse": "3.4.0" }, "engines": { - "node": ">= 14" + "node": ">= 12" + } + }, + "node_modules/@parse/push-adapter/node_modules/@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, + "node_modules/@parse/push-adapter/node_modules/@babel/runtime-corejs3": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz", + "integrity": "sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==", + "dependencies": { + "core-js-pure": "^3.15.0", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@parse/push-adapter/node_modules/idb-keyval": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-5.0.6.tgz", + "integrity": "sha512-6lJuVbwyo82mKSH6Wq2eHkt9LcbwHAelMIcMe0tP4p20Pod7tTxq9zf0ge2n/YDfMOpDryerfmmYyuQiaFaKOg==" + }, "node_modules/@parse/push-adapter/node_modules/parse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/parse/-/parse-4.2.0.tgz", - "integrity": "sha512-K8bWs0wM2qRhkSr6N16j8OvsF6Uallrynqng9e+tzR3RdKuB09vaJh48qrf9MbiJ1Ya4JZI7AfEHYF+ywEKs7Q==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.0.tgz", + "integrity": "sha512-FMZLxPW6PvrBgxkXc9AmnYsFKvPwiS4G2n9OI4mdfiSoNzIVLc+bXzlUdJ+I7hiqHsBTP0BrdQczw2/cnVkJ6w==", "dependencies": { - "@babel/runtime-corejs3": "7.21.0", - "idb-keyval": "6.2.0", + "@babel/runtime": "7.15.4", + "@babel/runtime-corejs3": "7.14.7", + "idb-keyval": "5.0.6", "react-native-crypto-js": "1.0.0", - "uuid": "9.0.0", - "ws": "8.13.0", + "uuid": "3.4.0", + "ws": "7.5.1", "xmlhttprequest": "1.8.0" }, - "engines": { - "node": ">=14.21.0 <17 || >=18 <20" - }, "optionalDependencies": { "crypto-js": "4.1.1" } }, + "node_modules/@parse/push-adapter/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/@parse/push-adapter/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", + "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==", "engines": { - "node": ">=10.0.0" + "node": ">=8.3.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -2899,9 +2983,9 @@ } }, "node_modules/@redis/client": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.12.tgz", - "integrity": "sha512-/ZjE18HRzMd80eXIIUIPcH81UoZpwulbo8FmbElrjPqH0QC0SeIKu1BOU49bO5trM5g895kAjhvalt5h77q+4A==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz", + "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==", "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -2912,33 +2996,33 @@ } }, "node_modules/@redis/graph": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", - "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/json": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz", - "integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/search": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.6.tgz", - "integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/time-series": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz", - "integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -3278,42 +3362,41 @@ } }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", + "@types/express-serve-static-core": "^4.17.31", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@types/range-parser": "*" } }, "node_modules/@types/http-cache-semantics": { @@ -3322,11 +3405,6 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -3334,17 +3412,17 @@ "dev": true }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", - "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -3370,14 +3448,14 @@ "dev": true }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/retry": { "version": "0.12.0", @@ -3385,21 +3463,11 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dependencies": { - "@types/http-errors": "*", "@types/mime": "*", "@types/node": "*" } @@ -3651,6 +3719,73 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/ampersand-events": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ampersand-events/-/ampersand-events-2.0.2.tgz", + "integrity": "sha512-pPnVEJviRxXi9YhZA9j3GwGGBTlDLi+YIoBvrpKXgce+CO1nMlZU2aOV8OJogNuR2YPbptAUHNz7SKX+MvLj8A==", + "dev": true, + "dependencies": { + "ampersand-version": "^1.0.2", + "lodash": "^4.6.1" + } + }, + "node_modules/ampersand-state": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/ampersand-state/-/ampersand-state-5.0.3.tgz", + "integrity": "sha512-sr904K5zvw6mkGjFHhTcfBIdpoJ6mn/HrFg7OleRmBpw3apLb3Z0gVrgRTb7kK1wOLI34vs4S+IXqNHUeqWCzw==", + "dev": true, + "dependencies": { + "ampersand-events": "^2.0.1", + "ampersand-version": "^1.0.0", + "array-next": "~0.0.1", + "key-tree-store": "^1.3.0", + "lodash": "^4.12.0" + } + }, + "node_modules/ampersand-version": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ampersand-version/-/ampersand-version-1.0.2.tgz", + "integrity": "sha512-FVVLY7Pghtgc8pQl0rF3A3+OS/CZ+/ILLMIYIaO1cA9v5SRkainqUMfSot3fu32svuThIsYK3q9iCsH9W5+mWQ==", + "dev": true, + "dependencies": { + "find-root": "^0.1.1", + "through2": "^0.6.3" + } + }, + "node_modules/ampersand-version/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/ampersand-version/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ampersand-version/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/ampersand-version/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", + "dev": true, + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, "node_modules/ansi": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", @@ -3990,6 +4125,12 @@ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, + "node_modules/array-next": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-next/-/array-next-0.0.1.tgz", + "integrity": "sha512-sBOC/Iaz2hCcYi2XlyRfyZCRUxamlE5NJXEFjE9BTx23HALnWAFsPjGtfrAclt9o3G/38Het2yyeyOd3CEY7lg==", + "dev": true + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -4230,7 +4371,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -4246,6 +4386,13 @@ } ] }, + "node_modules/bcrypt-nodejs": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", + "integrity": "sha512-NmTbLm867btBHCBZ222FQXkQKzecB0KG6pTXFa6NeTVZaSnLfCsx7EK2PL3J+kX8xJThUquEBbhimRCKKZX9zA==", + "deprecated": "bcrypt-nodejs is no longer actively maintained. Please use bcrypt or bcryptjs. See https://github.com/kelektiv/node.bcrypt.js/wiki/bcrypt-vs-brypt.js to learn more about these two options", + "dev": true + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -4423,18 +4570,20 @@ } }, "node_modules/bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", + "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", + "dependencies": { + "buffer": "^5.6.0" + }, "engines": { - "node": ">=14.20.1" + "node": ">=6.9.0" } }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -4726,6 +4875,21 @@ "node": ">= 8" } }, + "node_modules/caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "dependencies": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -4790,15 +4954,6 @@ "fsevents": "^1.2.7" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -4883,6 +5038,18 @@ "node": ">=6" } }, + "node_modules/cli-color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-0.3.2.tgz", + "integrity": "sha512-Ys/nDhHNRcxrS4EUI2RS/QCUE+61AMuEOj3sWDX+EIHkJWj+4XkRbOdwdxJteAJKjXYBbeFJMtfaEPd1MBF9pQ==", + "dev": true, + "dependencies": { + "d": "~0.1.1", + "es5-ext": "~0.10.2", + "memoizee": "0.3.x", + "timers-ext": "0.1.x" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -4970,6 +5137,15 @@ "node": ">=0.8" } }, + "node_modules/clui": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/clui/-/clui-0.3.6.tgz", + "integrity": "sha512-Z4UbgZILlIAjkEkZiDOa2aoYjohKx7fa6DxIh6cE9A6WNWZ61iXfQc6CmdC9SKdS5nO0P0UyQ+WfoXfB65e3HQ==", + "dev": true, + "dependencies": { + "cli-color": "0.3.2" + } + }, "node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -5139,6 +5315,22 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/connected-domain": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/connected-domain/-/connected-domain-1.0.0.tgz", + "integrity": "sha512-lHlohUiJxlpunvDag2Y0pO20bnvarMjnrdciZeuJUqRwrf/5JHNhdpiPIr5GQ8IkqrFj5TDMQwcCjblGo1oeuA==", + "dev": true + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -5445,6 +5637,15 @@ "node": "*" } }, + "node_modules/d": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha512-0SdM9V9pd/OXJHoWmTfNPTAeD+lw6ZqHg+isPyBFuJsZLSE0Ygg1cYZ/0l6DrKQXMOqGOu1oWupMoOfoRfMZrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -5863,6 +6064,14 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -6047,6 +6256,15 @@ "node": ">=8" } }, + "node_modules/docopt": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", + "integrity": "sha512-NqTbaYeE4gA/wU1hdKFdU+AFahpDOpgGLzHP42k6H6DKExJd0A55KEVWYhL9FEmHmgeLvEU2vuKXDuU+4yToOw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -6156,6 +6374,155 @@ "rimraf": "bin.js" } }, + "node_modules/download": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", + "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", + "dev": true, + "dependencies": { + "caw": "^2.0.0", + "content-disposition": "^0.5.2", + "decompress": "^4.0.0", + "ext-name": "^5.0.0", + "file-type": "5.2.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^7.0.0", + "make-dir": "^1.0.0", + "p-event": "^1.0.0", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "dependencies": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/download/node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/download/node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/p-event": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", + "integrity": "sha512-hV1zbA7gwqPVFcapfeATaNjQ3J0NuzorHPyG8GPL9g/Y/TplWVBVoCKCXL6Ej2zscrCEv195QNWJXuBH6XZuzA==", + "dev": true, + "dependencies": { + "p-timeout": "^1.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha512-gb0ryzr+K2qFqFv6qi3khoeqMZF/+ajxQipEF6NteZVnvz9tzdsfAVj3lYtn1gAXvH5lfLwfxEII799gt/mRIA==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/download/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/dset": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", @@ -6173,6 +6540,12 @@ "readable-stream": "^2.0.2" } }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -6357,6 +6730,39 @@ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, + "node_modules/es6-weak-map": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz", + "integrity": "sha512-P+N5Cd2TXeb7G59euFiM7snORspgbInS29Nbf3KNO2JQp/DyhvMCDWd58nsVAXwYJ6W3Bx7qDdy6QQ3PCJ7jKQ==", + "dev": true, + "dependencies": { + "d": "~0.1.1", + "es5-ext": "~0.10.6", + "es6-iterator": "~0.1.3", + "es6-symbol": "~2.0.1" + } + }, + "node_modules/es6-weak-map/node_modules/es6-iterator": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz", + "integrity": "sha512-6TOmbFM6OPWkTe+bQ3ZuUkvqcWUjAnYjKUCLdbvRsAUz2Pr+fYIibwNXNkLNtIK9PPFbNMZZddaRNkyJhlGJhA==", + "dev": true, + "dependencies": { + "d": "~0.1.1", + "es5-ext": "~0.10.5", + "es6-symbol": "~2.0.1" + } + }, + "node_modules/es6-weak-map/node_modules/es6-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz", + "integrity": "sha512-wjobO4zO8726HVU7mI2OA/B6QszqwHJuKab7gKHVx+uRfVVYGcWJkCIFxV2Madqb9/RUSrhJ/r6hPfG7FsWtow==", + "dev": true, + "dependencies": { + "d": "~0.1.1", + "es5-ext": "~0.10.5" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -7036,6 +7442,31 @@ "type": "^2.7.2" } }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -7364,6 +7795,29 @@ "dev": true, "optional": true }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/filing-cabinet": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/filing-cabinet/-/filing-cabinet-3.3.0.tgz", @@ -7560,6 +8014,12 @@ "semver": "bin/semver.js" } }, + "node_modules/find-root": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz", + "integrity": "sha512-GyDxVgA61TZcrgDJPqOqGBpi80Uf2yIstubgizi7AjC9yPdRrqBR+Y0MvK4kXnYlaoz3d+SGxDHMYVkwI/yd2w==", + "dev": true + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -7632,9 +8092,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "funding": [ { "type": "individual", @@ -7812,30 +8272,6 @@ "node": ">=10" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -7980,6 +8416,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-mongodb-version": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-mongodb-version/-/get-mongodb-version-2.0.1.tgz", + "integrity": "sha512-yTN0UY7VJSSt01QH/aCiqiBjfxcDrEdKeM3uXY6QR3sRARoftx36QT0YNsCQm7FDTgrmDje7bK2C9ClM7SGKDA==", + "dev": true, + "dependencies": { + "lodash.startswith": "^4.2.1", + "minimist": "^1.1.1", + "which": "^1.1.1" + }, + "bin": { + "get-mongodb-version": "bin/get-mongodb-version.js" + }, + "optionalDependencies": { + "mongodb": "*" + } + }, + "node_modules/get-mongodb-version/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -7995,6 +8460,18 @@ "node": ">=8.0.0" } }, + "node_modules/get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "dependencies": { + "npm-conf": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -8221,9 +8698,9 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -8350,6 +8827,15 @@ "node": ">=4" } }, + "node_modules/has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -8361,6 +8847,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "dependencies": { + "has-symbol-support-x": "^1.4.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -8773,7 +9271,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -8911,6 +9408,14 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, + "node_modules/ip-range-check": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ip-range-check/-/ip-range-check-0.2.0.tgz", + "integrity": "sha512-oaM3l/3gHbLlt/tCWLvt0mj1qUaI+STuRFnUvARGCujK9vvU61+2JsDpmkMzR4VsJhuFXWWgeKKVnwwoFfzCqw==", + "dependencies": { + "ipaddr.js": "^1.0.1" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -9054,6 +9559,37 @@ "node": ">=8" } }, + "node_modules/is-mongodb-running": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-mongodb-running/-/is-mongodb-running-1.0.2.tgz", + "integrity": "sha512-EslN8MErcBPExb+iK4RnG1n28JGjByA2Rm3YPmdHDGCRd7Hc2uvqshyVMAJXxbDSxRMy8vhxims2oRqQUeGJeA==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "debug": ">= 2.6.9", + "figures": "^2.0.0", + "lodash": "^4.17.10", + "lsof": "^0.1.0", + "minimist": "^1.2.0", + "node-netstat": "^1.4.2", + "ps-node": "^0.1.6" + }, + "bin": { + "is-mongodb-running": "bin/is-mongodb-running.js" + } + }, + "node_modules/is-mongodb-running/node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", @@ -9082,6 +9618,15 @@ "node": ">=8" } }, + "node_modules/is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -9137,6 +9682,15 @@ "integrity": "sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==", "dev": true }, + "node_modules/is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -9204,6 +9758,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -9423,6 +9986,19 @@ "node": ">=8" } }, + "node_modules/isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "dependencies": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + }, + "engines": { + "node": ">= 4" + } + }, "node_modules/iterall": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", @@ -9466,9 +10042,15 @@ } }, "node_modules/jose": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", - "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "dependencies": { + "@panva/asn1.js": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0 < 13 || >=13.7.0" + }, "funding": { "url": "https://github.com/sponsors/panva" } @@ -9715,14 +10297,6 @@ "extsprintf": "^1.2.0" } }, - "node_modules/jssha": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.1.tgz", - "integrity": "sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==", - "engines": { - "node": "*" - } - }, "node_modules/jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -9734,19 +10308,19 @@ } }, "node_modules/jwks-rsa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.1.0.tgz", - "integrity": "sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.5.tgz", + "integrity": "sha512-IODtn1SwEm7n6GQZnQLY0oxKDrMh7n/jRH1MzE8mlxWMrh2NnMyOsXTebu8vJ1qCpmuTJcL4DdiE0E4h8jnwsA==", "dependencies": { - "@types/express": "^4.17.17", - "@types/jsonwebtoken": "^9.0.2", + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^8.5.9", "debug": "^4.3.4", - "jose": "^4.14.6", + "jose": "^2.0.6", "limiter": "^1.1.5", - "lru-memoizer": "^2.2.0" + "lru-memoizer": "^2.1.4" }, "engines": { - "node": ">=14" + "node": ">=10 < 13 || >=14" } }, "node_modules/jws": { @@ -9758,6 +10332,12 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/key-tree-store": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/key-tree-store/-/key-tree-store-1.3.0.tgz", + "integrity": "sha512-qXk+lR+LXvGos3wqMxIMWweKDgCx8ZKWM6BEPm7iZkOKug5ggi66vUt+3vbtKJLBrAyOxQ4S8JRwK++Q4XZRmw==", + "dev": true + }, "node_modules/keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -9803,33 +10383,25 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, - "node_modules/ldap-filter": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz", - "integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/ldapjs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz", - "integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==", - "dependencies": { - "abstract-logging": "^2.0.0", - "asn1": "^0.2.4", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-3.0.2.tgz", + "integrity": "sha512-EBxQaBmgXk1DEaYYJWkp5i5PtSLRI2CWtm1gzxG5buOt40Q7j3zY6MbpRDkach/Cnxr3qSyLHiyXvvkLCOXw+Q==", + "dependencies": { + "@ldapjs/asn1": "2.0.0", + "@ldapjs/attribute": "1.0.0", + "@ldapjs/change": "1.0.0", + "@ldapjs/controls": "2.0.0", + "@ldapjs/dn": "1.0.0", + "@ldapjs/filter": "2.0.0", + "@ldapjs/messages": "1.0.2", + "@ldapjs/protocol": "^1.2.1", + "abstract-logging": "^2.0.1", "assert-plus": "^1.0.0", "backoff": "^2.5.0", - "ldap-filter": "^0.3.3", "once": "^1.4.0", - "vasync": "^2.2.0", - "verror": "^1.8.1" - }, - "engines": { - "node": ">=10.13.0" + "vasync": "^2.2.1", + "verror": "^1.10.1" } }, "node_modules/leven": { @@ -10252,6 +10824,12 @@ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, "node_modules/lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", @@ -10282,23 +10860,41 @@ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", "dev": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, "node_modules/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" }, "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, "node_modules/lodash.map": { "version": "4.6.0", @@ -10311,6 +10907,11 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/lodash.pad": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", @@ -10353,6 +10954,12 @@ "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", "dev": true }, + "node_modules/lodash.startswith": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz", + "integrity": "sha512-XClYR1h4/fJ7H+mmCKppbiBmljN/nGs73iq2SjCT9SF4CBPoUHzLvWmH1GtZMhMBZSiRkHXfeA2RY1eIlJ75ww==", + "dev": true + }, "node_modules/lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", @@ -10556,17 +11163,17 @@ } }, "node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", + "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", "engines": { "node": "14 || >=16.14" } }, "node_modules/lru-memoizer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", - "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", + "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", "dependencies": { "lodash.clonedeep": "^4.5.0", "lru-cache": "~4.0.0" @@ -10594,6 +11201,16 @@ "es5-ext": "~0.10.2" } }, + "node_modules/lsof": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lsof/-/lsof-0.1.0.tgz", + "integrity": "sha512-RlNW3s4gQ0CIlDM3jwfx/Ogdwpa8PHySyd5FnKKXfi2NPXEjqgwONyA0y9ax33ur1G+K+f192zzKNQljupSgNA==", + "deprecated": "No longer maintained", + "dev": true, + "engines": { + "node": ">= 0.2.0" + } + }, "node_modules/madge": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/madge/-/madge-5.0.1.tgz", @@ -10830,6 +11447,27 @@ "node": ">= 0.6" } }, + "node_modules/memoizee": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.3.10.tgz", + "integrity": "sha512-LLzVUuWwGBKK188spgOK/ukrp5zvd9JGsiLDH41pH9vt5jvhZfsu5pxDuAnYAMG8YEGce72KO07sSBy9KkvOfw==", + "dev": true, + "dependencies": { + "d": "~0.1.1", + "es5-ext": "~0.10.11", + "es6-weak-map": "~0.1.4", + "event-emitter": "~0.3.4", + "lru-queue": "0.1", + "next-tick": "~0.2.2", + "timers-ext": "0.1" + } + }, + "node_modules/memoizee/node_modules/next-tick": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz", + "integrity": "sha512-f7h4svPtl+QidoBv4taKXUjJ70G2asaZ8G28nS0OkqaalX8dwwrtWtyxEDPK62AC00ur/+/E0pUwBwY5EPn15Q==", + "dev": true + }, "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", @@ -11062,40 +11700,6 @@ "node": ">=0.10.0" } }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -11215,43 +11819,20 @@ } }, "node_modules/mongodb": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.0.tgz", - "integrity": "sha512-g+GCMHN1CoRUA+wb1Agv0TI4YTSiWr42B5ulkiAfLLHitGK1R+PkSAf3Lr5rPZwi/3F04LiaZEW0Kxro9Fi2TA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.10.0.tgz", + "integrity": "sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==", "dependencies": { - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" + "bson": "^4.7.0", + "denque": "^2.1.0", + "mongodb-connection-string-url": "^2.5.3", + "socks": "^2.7.0" }, "engines": { - "node": ">=14.20.1" + "node": ">=12.9.0" }, "optionalDependencies": { - "@mongodb-js/saslprep": "^1.1.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.0.0", - "kerberos": "^1.0.0 || ^2.0.0", - "mongodb-client-encryption": ">=2.3.0 <3", - "snappy": "^7.2.2" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - } + "saslprep": "^1.0.3" } }, "node_modules/mongodb-connection-string-url": { @@ -11263,10 +11844,82 @@ "whatwg-url": "^11.0.0" } }, + "node_modules/mongodb-core": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.7.tgz", + "integrity": "sha512-WypKdLxFNPOH/Jy6i9z47IjG2wIldA54iDZBmHMINcgKOUcWJh8og+Wix76oGd7EyYkHJKssQ2FAOw5Su/n4XQ==", + "dev": true, + "dependencies": { + "bson": "^1.1.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2" + }, + "optionalDependencies": { + "saslprep": "^1.0.0" + } + }, + "node_modules/mongodb-core/node_modules/bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/mongodb-dbpath": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/mongodb-dbpath/-/mongodb-dbpath-0.0.1.tgz", + "integrity": "sha512-JljM2Gci3LQgECY4Wnp8tRx6eDNSoTnqiz4TIaOfqLuPr3SAbSdZEAQomHniH8DQJpn97gxdYkW/XomxYPZM2w==", + "dev": true, + "dependencies": { + "async": "^1.4.0", + "debug": "^2.1.1", + "minimist": "^1.1.1", + "mkdirp": "^0.5.1", + "untildify": "^1.0.0" + }, + "bin": { + "mongodb-dbpath": "bin/mongodb-dbpath.js" + } + }, + "node_modules/mongodb-dbpath/node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true + }, + "node_modules/mongodb-dbpath/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/mongodb-dbpath/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/mongodb-dbpath/node_modules/untildify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-1.0.0.tgz", + "integrity": "sha512-LSU5BVpAncfzB2UBQaqfNww36wRSehWHs2grMM0ueYctZYxAhntiMvqDBhezYCYvbLeejeZ1nUWSl3mmkdPp+g==", + "dev": true, + "dependencies": { + "user-home": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/mongodb-download-url": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mongodb-download-url/-/mongodb-download-url-1.4.1.tgz", - "integrity": "sha512-OC0EGXiYTwZNcLq2U7Hbt1MDSPQR57/Kput4+W0F2kwVOa0HwWW4oY6DS1gOLlIeVOsihRKKH9EPNnc/BxF7UA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/mongodb-download-url/-/mongodb-download-url-1.2.2.tgz", + "integrity": "sha512-RD3jsswLVMkVp6QVudrKPLNMmiC1FHElTkTzU845K1Pr8ZL7M9HSBvVThXKrLT/WgChUHohEeCsmCmgeHW3ajQ==", "dev": true, "dependencies": { "debug": "^4.1.1", @@ -11279,9 +11932,9 @@ } }, "node_modules/mongodb-download-url/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -11321,119 +11974,184 @@ } }, "node_modules/mongodb-runner": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/mongodb-runner/-/mongodb-runner-5.4.4.tgz", - "integrity": "sha512-bODXH7sOMRXbpVceIR8zLnEgg9kv1eXW60pxW5dfNShkjWd+7wmalJY/Dm9LG1tcL7+O5H7lTZH+s32IWg+FVA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/mongodb-runner/-/mongodb-runner-4.8.1.tgz", + "integrity": "sha512-1jv7EEyh+ajvGmLwDMXY5BjT/Xqdxgf+AwPK99JHhgeoAISffS3l9Z1c/IIOsSCulMlL7KlR10TyUdzSHZqMhg==", "dev": true, "dependencies": { - "@mongodb-js/mongodb-downloader": "^0.2.8", - "debug": "^4.3.4", - "mongodb": "^5.6.0", - "mongodb-connection-string-url": "^2.6.0", - "yargs": "^17.7.2" + "async": "^3.1.0", + "clui": "^0.3.6", + "debug": "^4.1.1", + "fs-extra": "^8.1.0", + "is-mongodb-running": "^1.0.1", + "lodash.defaults": "^4.2.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "mongodb": "^3.4.0", + "mongodb-dbpath": "^0.0.1", + "mongodb-tools": "github:mongodb-js/mongodb-tools#0d1a90f49796c41f6d47c7c7999fe384014a16a0", + "mongodb-version-manager": "^1.4.3", + "untildify": "^4.0.0", + "which": "^2.0.1" }, "bin": { - "mongodb-runner": "bin/runner.js" + "mongodb-runner": "bin/mongodb-runner.js" } }, - "node_modules/mongodb-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/mongodb-runner/node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/mongodb-runner/node_modules/bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "dev": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.6.19" } }, - "node_modules/mongodb-runner/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/mongodb-runner/node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, "engines": { - "node": ">=12" + "node": ">=0.10" } }, - "node_modules/mongodb-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/mongodb-runner/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6 <7 || >=8" } }, - "node_modules/mongodb-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/mongodb-runner/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } }, - "node_modules/mongodb-runner/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/mongodb-runner/node_modules/mongodb": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", + "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2" }, "engines": { - "node": ">=10" + "node": ">=4" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "optionalDependencies": { + "saslprep": "^1.0.0" + }, + "peerDependenciesMeta": { + "aws4": { + "optional": true + }, + "bson-ext": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "mongodb-extjson": { + "optional": true + }, + "snappy": { + "optional": true + } } }, - "node_modules/mongodb-runner/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/mongodb-runner/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "engines": { - "node": ">=10" + "node": ">= 4.0.0" } }, - "node_modules/mongodb-runner/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/mongodb-tools": { + "version": "1.2.0", + "resolved": "git+ssh://git@github.com/mongodb-js/mongodb-tools.git#0d1a90f49796c41f6d47c7c7999fe384014a16a0", + "integrity": "sha512-DNJJQYg1/VcE4gNP7zpKeWGIezwcpkI8XzG4YFL3WybY6cuKWMz3d1CIp3uKKEpva1qOHk2LI8mKWJX1Vpw4Sg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "debug": "^2.2.0", + "lodash": "^4.17.12", + "mkdirp": "0.5.0", + "mongodb-core": "*", + "rimraf": "2.2.6" + } + }, + "node_modules/mongodb-tools/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/mongodb-tools/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "dev": true + }, + "node_modules/mongodb-tools/node_modules/mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha512-xjjNGy+ry1lhtIKcr2PT6ok3aszhQfgrUDp4OZLHacgRgFmF6XR9XCOJVcXlVGQonIqXcK1DvqgKKQOPWYGSfw==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "0.0.8" }, - "engines": { - "node": ">=12" + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/mongodb-runner/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/mongodb-tools/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/mongodb-tools/node_modules/rimraf": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.6.tgz", + "integrity": "sha512-33Fa/MIw/3F9KcDE/uJ2OuYUyxY+fkmw1c20DFnyhP7dfo2+BexeE1thjluPiJaG8sW6CcaqnTffwpRd4NAiTg==", "dev": true, - "engines": { - "node": ">=12" + "bin": { + "rimraf": "bin.js" } }, "node_modules/mongodb-version-list": { @@ -11506,6 +12224,84 @@ "semver": "bin/semver" } }, + "node_modules/mongodb-version-manager": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/mongodb-version-manager/-/mongodb-version-manager-1.4.6.tgz", + "integrity": "sha512-UxXZy7iqHUa039Bp8e1Y2tSLh/X/JtHRqnlcVkqNEWpX/5ETPaKwrT7QIVZc1Tk5tEkQXjRHd6nQtUjcemOHmA==", + "dev": true, + "dependencies": { + "ampersand-state": "^5.0.3", + "async": "^3.1.0", + "chalk": "^2.1.0", + "debug": ">= 2.6.9 < 3.0.0 || >= ^3.1.0", + "docopt": "^0.6.2", + "download": "^6.2.5", + "figures": "^3.2.0", + "fs-extra": "^8.1.0", + "get-mongodb-version": "^2.0.1", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.1.1", + "mongodb-download-url": "^1.0.0", + "mongodb-version-list": "^1.0.0", + "semver": "^5.3.0", + "tildify": "^2.0.0", + "untildify": "^4.0.0" + }, + "bin": { + "m": "bin/m.js", + "mongodb-version-manager": "bin/mongodb-version-manager.js" + } + }, + "node_modules/mongodb-version-manager/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/mongodb-version-manager/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/mongodb-version-manager/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/mongodb-version-manager/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/mongodb-version-manager/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -11527,16 +12323,10 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -11763,13 +12553,22 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.0.tgz", + "integrity": "sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==", "engines": { "node": ">= 6.13.0" } }, + "node_modules/node-netstat": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/node-netstat/-/node-netstat-1.8.0.tgz", + "integrity": "sha512-P1a5Sh9FfjTXxI6hC9q/Nqre8kT63FQxBCr1qz5ffk76EkQBH62+XEhIhlzfz6Bz+FRwOFqidW2FDGXnOXvyJQ==", + "dev": true, + "dependencies": { + "is-wsl": "^1.1.0" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -11992,6 +12791,28 @@ "node": ">=10" } }, + "node_modules/npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-conf/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -15067,6 +15888,18 @@ "node": ">=8" } }, + "node_modules/optional-require": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "dev": true, + "dependencies": { + "require-at": "^1.0.6" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -15176,17 +16009,6 @@ "node": ">=8" } }, - "node_modules/otpauth": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-9.2.1.tgz", - "integrity": "sha512-/MRvcm63pzK20NCsIOe8Btun42/yWNylPbUo/h5dMpSRJpoAJstWodEUjm4zUDeT1+Vbqif2E8IcP4trl1U4gQ==", - "dependencies": { - "jssha": "~3.3.1" - }, - "funding": { - "url": "https://github.com/hectorm/otpauth?sponsor=1" - } - }, "node_modules/p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", @@ -15229,6 +16051,15 @@ "node": ">=6" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/p-is-promise": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", @@ -15511,14 +16342,14 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/pg": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", - "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.0.tgz", + "integrity": "sha512-meLUVPn2TWgJyLmy7el3fQQVwft4gU5NGyvV0XbD41iU9Jbg8lCH4zexhIkihDzVHJStlt6r088G6/fWeNjhXA==", "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", - "pg-connection-string": "^2.6.2", - "pg-pool": "^3.6.1", + "pg-connection-string": "^2.6.0", + "pg-pool": "^3.6.0", "pg-protocol": "^1.6.0", "pg-types": "^2.1.0", "pgpass": "1.x" @@ -15527,7 +16358,7 @@ "node": ">= 8.0.0" }, "optionalDependencies": { - "pg-cloudflare": "^1.1.1" + "pg-cloudflare": "^1.1.0" }, "peerDependencies": { "pg-native": ">=3.0.1" @@ -15539,15 +16370,15 @@ } }, "node_modules/pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.0.tgz", + "integrity": "sha512-tGM8/s6frwuAIyRcJ6nWcIvd3+3NmUKIs6OjviIm1HPPFEt5MzQDOTBQyhPWg/m0kCl95M6gA1JaIXtS8KovOA==", "optional": true }, "node_modules/pg-connection-string": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.0.tgz", + "integrity": "sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==" }, "node_modules/pg-int8": { "version": "1.0.1", @@ -15632,20 +16463,20 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, "node_modules/pg-pool": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", - "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-promise": { - "version": "11.5.4", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.4.tgz", - "integrity": "sha512-esYSkDt2h6NQOkfotGAm1Ld5OjoITJLpB88Z1PIlcAU/RQ0XQE2PxW0bLJEOMHPGV5iaRnj1Y7ARznXbgN4FNw==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.0.tgz", + "integrity": "sha512-ZfhntV6Yoc3S0hQWOlEodk5fEmF9ADxKl0vNvBnZgzvLt73uY29wVaNBz2AZK2J0gVmm/zhO51RXPtI4MgKkSQ==", "dependencies": { "assert-options": "0.8.1", - "pg": "8.11.3", + "pg": "8.11.0", "pg-minify": "1.6.3", "spex": "3.3.0" }, @@ -15856,9 +16687,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", "dev": true, "funding": [ { @@ -15868,14 +16699,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -16019,6 +16846,15 @@ "node": ">= 0.8.0" } }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prettier": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", @@ -16063,6 +16899,11 @@ "node": ">=8" } }, + "node_modules/process-warning": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz", + "integrity": "sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -16074,6 +16915,12 @@ "react-is": "^16.13.1" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -16086,6 +16933,15 @@ "node": ">= 0.10" } }, + "node_modules/ps-node": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ps-node/-/ps-node-0.1.6.tgz", + "integrity": "sha512-w7QJhUTbu70hpDso0YXDRNKCPNuchV8UTUZsAv0m7Qj5g85oHOJfr9drA1EjvK4nQK/bG8P97W4L6PJ3IQLoOA==", + "dev": true, + "dependencies": { + "table-parser": "^0.1.3" + } + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -16566,16 +17422,16 @@ } }, "node_modules/redis": { - "version": "4.6.11", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.11.tgz", - "integrity": "sha512-kg1Lt4NZLYkAjPOj/WcyIGWfZfnyfKo1Wg9YKVSlzhFwxpFIl3LYI8BWy1Ab963LLDsTz2+OwdsesHKljB3WMQ==", + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz", + "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==", "dependencies": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.12", - "@redis/graph": "1.1.1", - "@redis/json": "1.0.6", - "@redis/search": "1.1.6", - "@redis/time-series": "1.0.5" + "@redis/client": "1.5.7", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" } }, "node_modules/regenerate": { @@ -16840,6 +17696,43 @@ "uuid": "bin/uuid" } }, + "node_modules/require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "dev": true, + "dependencies": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + } + }, + "node_modules/require_optional/node_modules/resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require_optional/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/require-at": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -17095,6 +17988,18 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/sass-lookup": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/sass-lookup/-/sass-lookup-3.0.0.tgz", @@ -17347,9 +18252,9 @@ } }, "node_modules/semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -17823,6 +18728,30 @@ "npm": ">= 3.0.0" } }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -18251,6 +19180,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stylus-lookup": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stylus-lookup/-/stylus-lookup-3.0.2.tgz", @@ -18383,6 +19324,15 @@ "node": ">=0.10" } }, + "node_modules/table-parser": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/table-parser/-/table-parser-0.1.3.tgz", + "integrity": "sha512-LCYeuvqqoPII3lzzYaXKbC3Forb+d2u4bNwhk/9FlivuGRxPE28YEWAYcujeSlLLDlMfvy29+WPybFJZFiKMYg==", + "dev": true, + "dependencies": { + "connected-domain": "^1.0.0" + } + }, "node_modules/taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", @@ -18398,23 +19348,6 @@ "node": ">=6" } }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -18443,18 +19376,6 @@ "safe-buffer": "^5.1.1" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/temp": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/temp/-/temp-0.4.0.tgz", @@ -18566,6 +19487,24 @@ "node": ">= 6" } }, + "node_modules/tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -18794,6 +19733,18 @@ "node": ">=8" } }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -19152,6 +20103,15 @@ "node": ">=0.10.0" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -19224,6 +20184,27 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, + "node_modules/url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==", + "dev": true, + "dependencies": { + "prepend-http": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -19243,6 +20224,18 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==", + "dev": true, + "bin": { + "user-home": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -19498,9 +20491,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "engines": { "node": ">=0.10.0" } @@ -19576,9 +20569,9 @@ } }, "node_modules/ws": { - "version": "8.15.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", - "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "engines": { "node": ">=10.0.0" }, @@ -19862,12 +20855,11 @@ } }, "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.18.6" } }, "@babel/compat-data": { @@ -19933,13 +20925,12 @@ } }, "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "requires": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -19975,9 +20966,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" }, "@babel/helper-explode-assignable-expression": { "version": "7.18.6", @@ -19989,20 +20980,20 @@ } }, "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" } }, "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.18.6" } }, "@babel/helper-member-expression-to-functions": { @@ -20083,22 +21074,22 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.18.6" } }, "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" }, "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -20128,19 +21119,19 @@ } }, "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" + "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", @@ -20967,39 +21958,39 @@ } }, "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.5", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, @@ -21381,61 +22372,85 @@ "lodash": "^4.17.21" } }, - "@mongodb-js/mongodb-downloader": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-downloader/-/mongodb-downloader-0.2.8.tgz", - "integrity": "sha512-y+mgw9QspvgTLRNHZJRS+DUTPk45RWpvYD1MaGDWhZ4ajffvxGqanY+Z4R6z01n+tIRmQvpShzF6zk+2Pr9d6w==", - "dev": true, + "@ldapjs/asn1": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-2.0.0.tgz", + "integrity": "sha512-G9+DkEOirNgdPmD0I8nu57ygQJKOOgFEMKknEuQvIHbGLwP3ny1mY+OTUYLCbCaGJP4sox5eYgBJRuSUpnAddA==" + }, + "@ldapjs/attribute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/attribute/-/attribute-1.0.0.tgz", + "integrity": "sha512-ptMl2d/5xJ0q+RgmnqOi3Zgwk/TMJYG7dYMC0Keko+yZU6n+oFM59MjQOUht5pxJeS4FWrImhu/LebX24vJNRQ==", "requires": { - "debug": "^4.3.4", - "decompress": "^4.2.1", - "mongodb-download-url": "^1.3.0", - "node-fetch": "^2.6.11", - "tar": "^6.1.15" + "@ldapjs/asn1": "2.0.0", + "@ldapjs/protocol": "^1.2.1", + "process-warning": "^2.1.0" + } + }, + "@ldapjs/change": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/change/-/change-1.0.0.tgz", + "integrity": "sha512-EOQNFH1RIku3M1s0OAJOzGfAohuFYXFY4s73wOhRm4KFGhmQQ7MChOh2YtYu9Kwgvuq1B0xKciXVzHCGkB5V+Q==", + "requires": { + "@ldapjs/asn1": "2.0.0", + "@ldapjs/attribute": "1.0.0" + } + }, + "@ldapjs/controls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/controls/-/controls-2.0.0.tgz", + "integrity": "sha512-NpFmdIc2q83tYRGR2a3NDulKgU1e4YOgqjQmmMezCoN4Xz0tju4yB4eibQNC+Zg8YRW06KPwFPKbebDaCqFF0w==", + "requires": { + "@ldapjs/asn1": "^1.2.0", + "@ldapjs/protocol": "^1.2.1" }, "dependencies": { - "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "@ldapjs/asn1": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-1.2.0.tgz", + "integrity": "sha512-KX/qQJ2xxzvO2/WOvr1UdQ+8P5dVvuOLk/C9b1bIkXxZss8BaR28njXdPgFCpj5aHaf1t8PmuVnea+N9YG9YMw==" } } }, - "@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", - "optional": true, + "@ldapjs/dn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/dn/-/dn-1.0.0.tgz", + "integrity": "sha512-qPsJDC5dQU2TSkA/IpswvPEg9MU6TIjjq0UOCHtuUeD3eWihTUjHuu/dith4NFRKjBvgFnqRQvo+t0YC+3z0Rw==", "requires": { - "sparse-bitfield": "^3.0.3" + "@ldapjs/asn1": "2.0.0", + "process-warning": "^2.1.0" + } + }, + "@ldapjs/filter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ldapjs/filter/-/filter-2.0.0.tgz", + "integrity": "sha512-7hMv5DNlHJk4qoGzCFGbbSV0vgvn2A7hZ4mt15557xDhw+BXjhryBvs8ANTHUpyaWvESbU+oNOsbBobNLZ45Nw==", + "requires": { + "@ldapjs/asn1": "2.0.0", + "@ldapjs/protocol": "^1.2.1", + "process-warning": "^2.1.0" + } + }, + "@ldapjs/messages": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@ldapjs/messages/-/messages-1.0.2.tgz", + "integrity": "sha512-aVYyqTDsIfnUt2Qr2syJi99M39h4ll9soggOtUjsf4Sv1xVQ/M5VY11T0h69S2fQ4NnaYi9iXd440LVU4MCCKQ==", + "requires": { + "@ldapjs/asn1": "2.0.0", + "@ldapjs/attribute": "1.0.0", + "@ldapjs/change": "1.0.0", + "@ldapjs/controls": "2.0.0", + "@ldapjs/dn": "1.0.0", + "@ldapjs/filter": "2.0.0", + "@ldapjs/protocol": "1.2.1", + "process-warning": "^2.1.0" } }, + "@ldapjs/protocol": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ldapjs/protocol/-/protocol-1.2.1.tgz", + "integrity": "sha512-O89xFDLW2gBoZWNXuXpBSM32/KealKCTb3JGtJdtUQc7RjAk8XzrRgyz02cPAwGKwKPxy0ivuC7UP9bmN87egQ==" + }, "@napi-rs/triples": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz", @@ -21711,19 +22726,24 @@ "@octokit/openapi-types": "^12.11.0" } }, + "@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==" + }, "@parse/fs-files-adapter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-2.0.1.tgz", - "integrity": "sha512-9DY0T9lK73Ysw+wxxsBt9rpxWxJpMlHl/fTW175XSajusW0ZP5jERI3BTKeclV28eVmSU690EO2vnwCURsPZ7g==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.2.tgz", + "integrity": "sha512-VUsVZXgt53FULqUd9xqGDW6RXes62qHXTNOeRSlS1MOemiCdtQOUGgLHgjdYQXnZ1hPLkxZKph96AluZUb953g==" }, "@parse/node-apn": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-6.0.1.tgz", - "integrity": "sha512-QQxqEN/zbtEkSgj41oX/tQUavML+G+JHeQi2YVlgZlponnwIxA3fb5tEbXPm+fdR6rL1pi2/z2PcOwINOyx2eA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@parse/node-apn/-/node-apn-5.1.3.tgz", + "integrity": "sha512-Bwhmbm895lEIF2772PJ8dSvBjrtOG9/q/TDMxmX40IgZxQFoXS73+JUIKTq3CA7SUB/Szu5roJINQ0L2U/1MJw==", "requires": { "debug": "4.3.3", - "jsonwebtoken": "9.0.0", - "node-forge": "1.3.1", + "jsonwebtoken": "8.5.1", + "node-forge": "1.3.0", "verror": "1.10.1" }, "dependencies": { @@ -21734,6 +22754,28 @@ "requires": { "ms": "2.1.2" } + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -21758,34 +22800,62 @@ } }, "@parse/push-adapter": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-5.0.2.tgz", - "integrity": "sha512-0nVBGj8p8cYGjoMdkVAlsa/UlB1Z4W6Ch7MEVcEfnyCmJBw6bvHwB1VVWoclcRqi3phsu3SizR5zVvB/Cx8I/g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@parse/push-adapter/-/push-adapter-4.1.3.tgz", + "integrity": "sha512-Oy53ag7DpUva5dUWwP6tNEsrxv2xU9QIk+rb84q1DIm1qVgo2yl4oXcZ3FPG2Ks/NYURbv4w+z9oaSgVfyBRfQ==", "requires": { - "@parse/node-apn": "6.0.1", + "@parse/node-apn": "5.1.3", "@parse/node-gcm": "1.0.2", "npmlog": "4.1.2", - "parse": "4.2.0" + "parse": "3.4.0" }, "dependencies": { + "@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.7.tgz", + "integrity": "sha512-Wvzcw4mBYbTagyBVZpAJWI06auSIj033T/yNE0Zn1xcup83MieCddZA7ls3kme17L4NOGBrQ09Q+nKB41RLWBA==", + "requires": { + "core-js-pure": "^3.15.0", + "regenerator-runtime": "^0.13.4" + } + }, + "idb-keyval": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-5.0.6.tgz", + "integrity": "sha512-6lJuVbwyo82mKSH6Wq2eHkt9LcbwHAelMIcMe0tP4p20Pod7tTxq9zf0ge2n/YDfMOpDryerfmmYyuQiaFaKOg==" + }, "parse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/parse/-/parse-4.2.0.tgz", - "integrity": "sha512-K8bWs0wM2qRhkSr6N16j8OvsF6Uallrynqng9e+tzR3RdKuB09vaJh48qrf9MbiJ1Ya4JZI7AfEHYF+ywEKs7Q==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/parse/-/parse-3.4.0.tgz", + "integrity": "sha512-FMZLxPW6PvrBgxkXc9AmnYsFKvPwiS4G2n9OI4mdfiSoNzIVLc+bXzlUdJ+I7hiqHsBTP0BrdQczw2/cnVkJ6w==", "requires": { - "@babel/runtime-corejs3": "7.21.0", + "@babel/runtime": "7.15.4", + "@babel/runtime-corejs3": "7.14.7", "crypto-js": "4.1.1", - "idb-keyval": "6.2.0", + "idb-keyval": "5.0.6", "react-native-crypto-js": "1.0.0", - "uuid": "9.0.0", - "ws": "8.13.0", + "uuid": "3.4.0", + "ws": "7.5.1", "xmlhttprequest": "1.8.0" } }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", + "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==", "requires": {} } } @@ -21797,9 +22867,9 @@ "requires": {} }, "@redis/client": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.12.tgz", - "integrity": "sha512-/ZjE18HRzMd80eXIIUIPcH81UoZpwulbo8FmbElrjPqH0QC0SeIKu1BOU49bO5trM5g895kAjhvalt5h77q+4A==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz", + "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==", "requires": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -21807,27 +22877,27 @@ } }, "@redis/graph": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", - "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", "requires": {} }, "@redis/json": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz", - "integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", "requires": {} }, "@redis/search": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.6.tgz", - "integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", "requires": {} }, "@redis/time-series": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz", - "integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", "requires": {} }, "@repeaterjs/repeater": { @@ -22084,42 +23154,41 @@ "dev": true }, "@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "requires": { "@types/connect": "*", "@types/node": "*" } }, "@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "requires": { "@types/node": "*" } }, "@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", + "@types/express-serve-static-core": "^4.17.31", "@types/qs": "*", "@types/serve-static": "*" } }, "@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "requires": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@types/range-parser": "*" } }, "@types/http-cache-semantics": { @@ -22128,11 +23197,6 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, - "@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -22140,17 +23204,17 @@ "dev": true }, "@types/jsonwebtoken": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", - "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", "requires": { "@types/node": "*" } }, "@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "@types/minimist": { "version": "1.2.2", @@ -22176,14 +23240,14 @@ "dev": true }, "@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, "@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/retry": { "version": "0.12.0", @@ -22191,21 +23255,11 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, "@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "requires": { - "@types/http-errors": "*", "@types/mime": "*", "@types/node": "*" } @@ -22385,6 +23439,75 @@ } } }, + "ampersand-events": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ampersand-events/-/ampersand-events-2.0.2.tgz", + "integrity": "sha512-pPnVEJviRxXi9YhZA9j3GwGGBTlDLi+YIoBvrpKXgce+CO1nMlZU2aOV8OJogNuR2YPbptAUHNz7SKX+MvLj8A==", + "dev": true, + "requires": { + "ampersand-version": "^1.0.2", + "lodash": "^4.6.1" + } + }, + "ampersand-state": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/ampersand-state/-/ampersand-state-5.0.3.tgz", + "integrity": "sha512-sr904K5zvw6mkGjFHhTcfBIdpoJ6mn/HrFg7OleRmBpw3apLb3Z0gVrgRTb7kK1wOLI34vs4S+IXqNHUeqWCzw==", + "dev": true, + "requires": { + "ampersand-events": "^2.0.1", + "ampersand-version": "^1.0.0", + "array-next": "~0.0.1", + "key-tree-store": "^1.3.0", + "lodash": "^4.12.0" + } + }, + "ampersand-version": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ampersand-version/-/ampersand-version-1.0.2.tgz", + "integrity": "sha512-FVVLY7Pghtgc8pQl0rF3A3+OS/CZ+/ILLMIYIaO1cA9v5SRkainqUMfSot3fu32svuThIsYK3q9iCsH9W5+mWQ==", + "dev": true, + "requires": { + "find-root": "^0.1.1", + "through2": "^0.6.3" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, "ansi": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", @@ -22652,6 +23775,12 @@ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, + "array-next": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-next/-/array-next-0.0.1.tgz", + "integrity": "sha512-sBOC/Iaz2hCcYi2XlyRfyZCRUxamlE5NJXEFjE9BTx23HALnWAFsPjGtfrAclt9o3G/38Het2yyeyOd3CEY7lg==", + "dev": true + }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -22836,7 +23965,12 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bcrypt-nodejs": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", + "integrity": "sha512-NmTbLm867btBHCBZ222FQXkQKzecB0KG6pTXFa6NeTVZaSnLfCsx7EK2PL3J+kX8xJThUquEBbhimRCKKZX9zA==", "dev": true }, "bcrypt-pbkdf": { @@ -22991,15 +24125,17 @@ } }, "bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==" + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", + "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", + "requires": { + "buffer": "^5.6.0" + } }, "buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -23208,6 +24344,18 @@ "lodash": "^4.17.14" } }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -23263,12 +24411,6 @@ "upath": "^1.1.1" } }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true - }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -23339,6 +24481,18 @@ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, + "cli-color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-0.3.2.tgz", + "integrity": "sha512-Ys/nDhHNRcxrS4EUI2RS/QCUE+61AMuEOj3sWDX+EIHkJWj+4XkRbOdwdxJteAJKjXYBbeFJMtfaEPd1MBF9pQ==", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.2", + "memoizee": "0.3.x", + "timers-ext": "0.1.x" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -23400,6 +24554,15 @@ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true }, + "clui": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/clui/-/clui-0.3.6.tgz", + "integrity": "sha512-Z4UbgZILlIAjkEkZiDOa2aoYjohKx7fa6DxIh6cE9A6WNWZ61iXfQc6CmdC9SKdS5nO0P0UyQ+WfoXfB65e3HQ==", + "dev": true, + "requires": { + "cli-color": "0.3.2" + } + }, "cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -23538,6 +24701,22 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "connected-domain": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/connected-domain/-/connected-domain-1.0.0.tgz", + "integrity": "sha512-lHlohUiJxlpunvDag2Y0pO20bnvarMjnrdciZeuJUqRwrf/5JHNhdpiPIr5GQ8IkqrFj5TDMQwcCjblGo1oeuA==", + "dev": true + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -23771,6 +24950,15 @@ "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", "dev": true }, + "d": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha512-0SdM9V9pd/OXJHoWmTfNPTAeD+lw6ZqHg+isPyBFuJsZLSE0Ygg1cYZ/0l6DrKQXMOqGOu1oWupMoOfoRfMZrQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -24088,6 +25276,11 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -24233,6 +25426,12 @@ "path-type": "^4.0.0" } }, + "docopt": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", + "integrity": "sha512-NqTbaYeE4gA/wU1hdKFdU+AFahpDOpgGLzHP42k6H6DKExJd0A55KEVWYhL9FEmHmgeLvEU2vuKXDuU+4yToOw==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -24335,6 +25534,121 @@ } } }, + "download": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", + "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", + "dev": true, + "requires": { + "caw": "^2.0.0", + "content-disposition": "^0.5.2", + "decompress": "^4.0.0", + "ext-name": "^5.0.0", + "file-type": "5.2.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^7.0.0", + "make-dir": "^1.0.0", + "p-event": "^1.0.0", + "pify": "^3.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "p-event": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", + "integrity": "sha512-hV1zbA7gwqPVFcapfeATaNjQ3J0NuzorHPyG8GPL9g/Y/TplWVBVoCKCXL6Ej2zscrCEv195QNWJXuBH6XZuzA==", + "dev": true, + "requires": { + "p-timeout": "^1.1.1" + } + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha512-gb0ryzr+K2qFqFv6qi3khoeqMZF/+ajxQipEF6NteZVnvz9tzdsfAVj3lYtn1gAXvH5lfLwfxEII799gt/mRIA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true + } + } + }, "dset": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", @@ -24349,6 +25663,12 @@ "readable-stream": "^2.0.2" } }, + "duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -24518,6 +25838,41 @@ } } }, + "es6-weak-map": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz", + "integrity": "sha512-P+N5Cd2TXeb7G59euFiM7snORspgbInS29Nbf3KNO2JQp/DyhvMCDWd58nsVAXwYJ6W3Bx7qDdy6QQ3PCJ7jKQ==", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.6", + "es6-iterator": "~0.1.3", + "es6-symbol": "~2.0.1" + }, + "dependencies": { + "es6-iterator": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz", + "integrity": "sha512-6TOmbFM6OPWkTe+bQ3ZuUkvqcWUjAnYjKUCLdbvRsAUz2Pr+fYIibwNXNkLNtIK9PPFbNMZZddaRNkyJhlGJhA==", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.5", + "es6-symbol": "~2.0.1" + } + }, + "es6-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz", + "integrity": "sha512-wjobO4zO8726HVU7mI2OA/B6QszqwHJuKab7gKHVx+uRfVVYGcWJkCIFxV2Madqb9/RUSrhJ/r6hPfG7FsWtow==", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.5" + } + } + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -25032,6 +26387,25 @@ "type": "^2.7.2" } }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -25278,6 +26652,23 @@ "dev": true, "optional": true }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, "filing-cabinet": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/filing-cabinet/-/filing-cabinet-3.3.0.tgz", @@ -25429,6 +26820,12 @@ } } }, + "find-root": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz", + "integrity": "sha512-GyDxVgA61TZcrgDJPqOqGBpi80Uf2yIstubgizi7AjC9yPdRrqBR+Y0MvK4kXnYlaoz3d+SGxDHMYVkwI/yd2w==", + "dev": true + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -25479,9 +26876,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, "for-in": { "version": "1.0.2", @@ -25600,26 +26997,6 @@ "universalify": "^2.0.0" } }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, "fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -25731,6 +27108,29 @@ "has-symbols": "^1.0.3" } }, + "get-mongodb-version": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-mongodb-version/-/get-mongodb-version-2.0.1.tgz", + "integrity": "sha512-yTN0UY7VJSSt01QH/aCiqiBjfxcDrEdKeM3uXY6QR3sRARoftx36QT0YNsCQm7FDTgrmDje7bK2C9ClM7SGKDA==", + "dev": true, + "requires": { + "lodash.startswith": "^4.2.1", + "minimist": "^1.1.1", + "mongodb": "*", + "which": "^1.1.1" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -25743,6 +27143,15 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "requires": { + "npm-conf": "^1.1.0" + } + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -25928,9 +27337,9 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, "graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==" + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==" }, "graphql-list-fields": { "version": "2.0.2", @@ -26015,11 +27424,26 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -26342,8 +27766,7 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "5.2.4", @@ -26442,6 +27865,14 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, + "ip-range-check": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ip-range-check/-/ip-range-check-0.2.0.tgz", + "integrity": "sha512-oaM3l/3gHbLlt/tCWLvt0mj1qUaI+STuRFnUvARGCujK9vvU61+2JsDpmkMzR4VsJhuFXWWgeKKVnwwoFfzCqw==", + "requires": { + "ipaddr.js": "^1.0.1" + } + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -26551,6 +27982,33 @@ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, + "is-mongodb-running": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-mongodb-running/-/is-mongodb-running-1.0.2.tgz", + "integrity": "sha512-EslN8MErcBPExb+iK4RnG1n28JGjByA2Rm3YPmdHDGCRd7Hc2uvqshyVMAJXxbDSxRMy8vhxims2oRqQUeGJeA==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "debug": ">= 2.6.9", + "figures": "^2.0.0", + "lodash": "^4.17.10", + "lsof": "^0.1.0", + "minimist": "^1.2.0", + "node-netstat": "^1.4.2", + "ps-node": "^0.1.6" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } + } + }, "is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", @@ -26573,6 +28031,12 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, + "is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -26613,6 +28077,12 @@ "integrity": "sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==", "dev": true }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -26656,6 +28126,12 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -26829,6 +28305,16 @@ "istanbul-lib-report": "^3.0.0" } }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, "iterall": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", @@ -26866,9 +28352,12 @@ "dev": true }, "jose": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", - "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "requires": { + "@panva/asn1.js": "^1.0.0" + } }, "js-sdsl": { "version": "4.2.0", @@ -27061,11 +28550,6 @@ } } }, - "jssha": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.1.tgz", - "integrity": "sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==" - }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -27077,16 +28561,16 @@ } }, "jwks-rsa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.1.0.tgz", - "integrity": "sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.5.tgz", + "integrity": "sha512-IODtn1SwEm7n6GQZnQLY0oxKDrMh7n/jRH1MzE8mlxWMrh2NnMyOsXTebu8vJ1qCpmuTJcL4DdiE0E4h8jnwsA==", "requires": { - "@types/express": "^4.17.17", - "@types/jsonwebtoken": "^9.0.2", + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^8.5.9", "debug": "^4.3.4", - "jose": "^4.14.6", + "jose": "^2.0.6", "limiter": "^1.1.5", - "lru-memoizer": "^2.2.0" + "lru-memoizer": "^2.1.4" } }, "jws": { @@ -27098,6 +28582,12 @@ "safe-buffer": "^5.0.1" } }, + "key-tree-store": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/key-tree-store/-/key-tree-store-1.3.0.tgz", + "integrity": "sha512-qXk+lR+LXvGos3wqMxIMWweKDgCx8ZKWM6BEPm7iZkOKug5ggi66vUt+3vbtKJLBrAyOxQ4S8JRwK++Q4XZRmw==", + "dev": true + }, "keyv": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", @@ -27140,27 +28630,25 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, - "ldap-filter": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz", - "integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==", - "requires": { - "assert-plus": "^1.0.0" - } - }, "ldapjs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz", - "integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==", - "requires": { - "abstract-logging": "^2.0.0", - "asn1": "^0.2.4", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-3.0.2.tgz", + "integrity": "sha512-EBxQaBmgXk1DEaYYJWkp5i5PtSLRI2CWtm1gzxG5buOt40Q7j3zY6MbpRDkach/Cnxr3qSyLHiyXvvkLCOXw+Q==", + "requires": { + "@ldapjs/asn1": "2.0.0", + "@ldapjs/attribute": "1.0.0", + "@ldapjs/change": "1.0.0", + "@ldapjs/controls": "2.0.0", + "@ldapjs/dn": "1.0.0", + "@ldapjs/filter": "2.0.0", + "@ldapjs/messages": "1.0.2", + "@ldapjs/protocol": "^1.2.1", + "abstract-logging": "^2.0.1", "assert-plus": "^1.0.0", "backoff": "^2.5.0", - "ldap-filter": "^0.3.3", "once": "^1.4.0", - "vasync": "^2.2.0", - "verror": "^1.8.1" + "vasync": "^2.2.1", + "verror": "^1.10.1" } }, "leven": { @@ -27487,6 +28975,12 @@ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, "lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", @@ -27517,23 +29011,41 @@ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, "lodash.map": { "version": "4.6.0", @@ -27546,6 +29058,11 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "lodash.pad": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", @@ -27588,6 +29105,12 @@ "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", "dev": true }, + "lodash.startswith": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz", + "integrity": "sha512-XClYR1h4/fJ7H+mmCKppbiBmljN/nGs73iq2SjCT9SF4CBPoUHzLvWmH1GtZMhMBZSiRkHXfeA2RY1eIlJ75ww==", + "dev": true + }, "lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", @@ -27738,14 +29261,14 @@ "dev": true }, "lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", + "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==" }, "lru-memoizer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", - "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", + "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", "requires": { "lodash.clonedeep": "^4.5.0", "lru-cache": "~4.0.0" @@ -27775,6 +29298,12 @@ "es5-ext": "~0.10.2" } }, + "lsof": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lsof/-/lsof-0.1.0.tgz", + "integrity": "sha512-RlNW3s4gQ0CIlDM3jwfx/Ogdwpa8PHySyd5FnKKXfi2NPXEjqgwONyA0y9ax33ur1G+K+f192zzKNQljupSgNA==", + "dev": true + }, "madge": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/madge/-/madge-5.0.1.tgz", @@ -27951,6 +29480,29 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, + "memoizee": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.3.10.tgz", + "integrity": "sha512-LLzVUuWwGBKK188spgOK/ukrp5zvd9JGsiLDH41pH9vt5jvhZfsu5pxDuAnYAMG8YEGce72KO07sSBy9KkvOfw==", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.11", + "es6-weak-map": "~0.1.4", + "event-emitter": "~0.3.4", + "lru-queue": "0.1", + "next-tick": "~0.2.2", + "timers-ext": "0.1" + }, + "dependencies": { + "next-tick": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz", + "integrity": "sha512-f7h4svPtl+QidoBv4taKXUjJ70G2asaZ8G28nS0OkqaalX8dwwrtWtyxEDPK62AC00ur/+/E0pUwBwY5EPn15Q==", + "dev": true + } + } + }, "memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", @@ -28120,33 +29672,6 @@ } } }, - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -28238,14 +29763,15 @@ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "mongodb": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.0.tgz", - "integrity": "sha512-g+GCMHN1CoRUA+wb1Agv0TI4YTSiWr42B5ulkiAfLLHitGK1R+PkSAf3Lr5rPZwi/3F04LiaZEW0Kxro9Fi2TA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.10.0.tgz", + "integrity": "sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==", "requires": { - "@mongodb-js/saslprep": "^1.1.0", - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" + "bson": "^4.7.0", + "denque": "^2.1.0", + "mongodb-connection-string-url": "^2.5.3", + "saslprep": "^1.0.3", + "socks": "^2.7.0" } }, "mongodb-connection-string-url": { @@ -28257,10 +29783,75 @@ "whatwg-url": "^11.0.0" } }, + "mongodb-core": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.7.tgz", + "integrity": "sha512-WypKdLxFNPOH/Jy6i9z47IjG2wIldA54iDZBmHMINcgKOUcWJh8og+Wix76oGd7EyYkHJKssQ2FAOw5Su/n4XQ==", + "dev": true, + "requires": { + "bson": "^1.1.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + }, + "dependencies": { + "bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "dev": true + } + } + }, + "mongodb-dbpath": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/mongodb-dbpath/-/mongodb-dbpath-0.0.1.tgz", + "integrity": "sha512-JljM2Gci3LQgECY4Wnp8tRx6eDNSoTnqiz4TIaOfqLuPr3SAbSdZEAQomHniH8DQJpn97gxdYkW/XomxYPZM2w==", + "dev": true, + "requires": { + "async": "^1.4.0", + "debug": "^2.1.1", + "minimist": "^1.1.1", + "mkdirp": "^0.5.1", + "untildify": "^1.0.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "untildify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-1.0.0.tgz", + "integrity": "sha512-LSU5BVpAncfzB2UBQaqfNww36wRSehWHs2grMM0ueYctZYxAhntiMvqDBhezYCYvbLeejeZ1nUWSl3mmkdPp+g==", + "dev": true, + "requires": { + "user-home": "^1.0.0" + } + } + } + }, "mongodb-download-url": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mongodb-download-url/-/mongodb-download-url-1.4.1.tgz", - "integrity": "sha512-OC0EGXiYTwZNcLq2U7Hbt1MDSPQR57/Kput4+W0F2kwVOa0HwWW4oY6DS1gOLlIeVOsihRKKH9EPNnc/BxF7UA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/mongodb-download-url/-/mongodb-download-url-1.2.2.tgz", + "integrity": "sha512-RD3jsswLVMkVp6QVudrKPLNMmiC1FHElTkTzU845K1Pr8ZL7M9HSBvVThXKrLT/WgChUHohEeCsmCmgeHW3ajQ==", "dev": true, "requires": { "debug": "^4.1.1", @@ -28270,9 +29861,9 @@ }, "dependencies": { "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, "requires": { "whatwg-url": "^5.0.0" @@ -28303,89 +29894,138 @@ } }, "mongodb-runner": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/mongodb-runner/-/mongodb-runner-5.4.4.tgz", - "integrity": "sha512-bODXH7sOMRXbpVceIR8zLnEgg9kv1eXW60pxW5dfNShkjWd+7wmalJY/Dm9LG1tcL7+O5H7lTZH+s32IWg+FVA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/mongodb-runner/-/mongodb-runner-4.8.1.tgz", + "integrity": "sha512-1jv7EEyh+ajvGmLwDMXY5BjT/Xqdxgf+AwPK99JHhgeoAISffS3l9Z1c/IIOsSCulMlL7KlR10TyUdzSHZqMhg==", "dev": true, "requires": { - "@mongodb-js/mongodb-downloader": "^0.2.8", - "debug": "^4.3.4", - "mongodb": "^5.6.0", - "mongodb-connection-string-url": "^2.6.0", - "yargs": "^17.7.2" + "async": "^3.1.0", + "clui": "^0.3.6", + "debug": "^4.1.1", + "fs-extra": "^8.1.0", + "is-mongodb-running": "^1.0.1", + "lodash.defaults": "^4.2.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "mongodb": "^3.4.0", + "mongodb-dbpath": "^0.0.1", + "mongodb-tools": "github:mongodb-js/mongodb-tools#0d1a90f49796c41f6d47c7c7999fe384014a16a0", + "mongodb-version-manager": "^1.4.3", + "untildify": "^4.0.0", + "which": "^2.0.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" } }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "dev": true + }, + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "graceful-fs": "^4.1.6" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "mongodb": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", + "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "dev": true, + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "mongodb-tools": { + "version": "git+ssh://git@github.com/mongodb-js/mongodb-tools.git#0d1a90f49796c41f6d47c7c7999fe384014a16a0", + "integrity": "sha512-DNJJQYg1/VcE4gNP7zpKeWGIezwcpkI8XzG4YFL3WybY6cuKWMz3d1CIp3uKKEpva1qOHk2LI8mKWJX1Vpw4Sg==", + "dev": true, + "from": "mongodb-tools@github:mongodb-js/mongodb-tools#0d1a90f49796c41f6d47c7c7999fe384014a16a0", + "requires": { + "debug": "^2.2.0", + "lodash": "^4.17.12", + "mkdirp": "0.5.0", + "mongodb-core": "*", + "rimraf": "2.2.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ms": "2.0.0" } }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", "dev": true }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha512-xjjNGy+ry1lhtIKcr2PT6ok3aszhQfgrUDp4OZLHacgRgFmF6XR9XCOJVcXlVGQonIqXcK1DvqgKKQOPWYGSfw==", "dev": true, "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "minimist": "0.0.8" } }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "rimraf": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.6.tgz", + "integrity": "sha512-33Fa/MIw/3F9KcDE/uJ2OuYUyxY+fkmw1c20DFnyhP7dfo2+BexeE1thjluPiJaG8sW6CcaqnTffwpRd4NAiTg==", "dev": true } } @@ -28456,6 +30096,73 @@ } } }, + "mongodb-version-manager": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/mongodb-version-manager/-/mongodb-version-manager-1.4.6.tgz", + "integrity": "sha512-UxXZy7iqHUa039Bp8e1Y2tSLh/X/JtHRqnlcVkqNEWpX/5ETPaKwrT7QIVZc1Tk5tEkQXjRHd6nQtUjcemOHmA==", + "dev": true, + "requires": { + "ampersand-state": "^5.0.3", + "async": "^3.1.0", + "chalk": "^2.1.0", + "debug": ">= 2.6.9 < 3.0.0 || >= ^3.1.0", + "docopt": "^0.6.2", + "download": "^6.2.5", + "figures": "^3.2.0", + "fs-extra": "^8.1.0", + "get-mongodb-version": "^2.0.1", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.1.1", + "mongodb-download-url": "^1.0.0", + "mongodb-version-list": "^1.0.0", + "semver": "^5.3.0", + "tildify": "^2.0.0", + "untildify": "^4.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -28474,9 +30181,9 @@ "optional": true }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true }, "nanomatch": { @@ -28650,9 +30357,18 @@ } }, "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.0.tgz", + "integrity": "sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==" + }, + "node-netstat": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/node-netstat/-/node-netstat-1.8.0.tgz", + "integrity": "sha512-P1a5Sh9FfjTXxI6hC9q/Nqre8kT63FQxBCr1qz5ffk76EkQBH62+XEhIhlzfz6Bz+FRwOFqidW2FDGXnOXvyJQ==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } }, "node-preload": { "version": "0.2.1", @@ -30789,6 +32505,24 @@ } } }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true + } + } + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -31039,6 +32773,15 @@ } } }, + "optional-require": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "dev": true, + "requires": { + "require-at": "^1.0.6" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -31120,14 +32863,6 @@ } } }, - "otpauth": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-9.2.1.tgz", - "integrity": "sha512-/MRvcm63pzK20NCsIOe8Btun42/yWNylPbUo/h5dMpSRJpoAJstWodEUjm4zUDeT1+Vbqif2E8IcP4trl1U4gQ==", - "requires": { - "jssha": "~3.3.1" - } - }, "p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", @@ -31157,6 +32892,12 @@ } } }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, "p-is-promise": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", @@ -31356,30 +33097,30 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "pg": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", - "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.0.tgz", + "integrity": "sha512-meLUVPn2TWgJyLmy7el3fQQVwft4gU5NGyvV0XbD41iU9Jbg8lCH4zexhIkihDzVHJStlt6r088G6/fWeNjhXA==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", - "pg-cloudflare": "^1.1.1", - "pg-connection-string": "^2.6.2", - "pg-pool": "^3.6.1", + "pg-cloudflare": "^1.1.0", + "pg-connection-string": "^2.6.0", + "pg-pool": "^3.6.0", "pg-protocol": "^1.6.0", "pg-types": "^2.1.0", "pgpass": "1.x" } }, "pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.0.tgz", + "integrity": "sha512-tGM8/s6frwuAIyRcJ6nWcIvd3+3NmUKIs6OjviIm1HPPFEt5MzQDOTBQyhPWg/m0kCl95M6gA1JaIXtS8KovOA==", "optional": true }, "pg-connection-string": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.0.tgz", + "integrity": "sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==" }, "pg-int8": { "version": "1.0.1", @@ -31454,18 +33195,18 @@ } }, "pg-pool": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", - "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", "requires": {} }, "pg-promise": { - "version": "11.5.4", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.4.tgz", - "integrity": "sha512-esYSkDt2h6NQOkfotGAm1Ld5OjoITJLpB88Z1PIlcAU/RQ0XQE2PxW0bLJEOMHPGV5iaRnj1Y7ARznXbgN4FNw==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.0.tgz", + "integrity": "sha512-ZfhntV6Yoc3S0hQWOlEodk5fEmF9ADxKl0vNvBnZgzvLt73uY29wVaNBz2AZK2J0gVmm/zhO51RXPtI4MgKkSQ==", "requires": { "assert-options": "0.8.1", - "pg": "8.11.3", + "pg": "8.11.0", "pg-minify": "1.6.3", "spex": "3.3.0" } @@ -31626,12 +33367,12 @@ "optional": true }, "postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", "dev": true, "requires": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -31740,6 +33481,12 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", + "dev": true + }, "prettier": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", @@ -31769,6 +33516,11 @@ "fromentries": "^1.2.0" } }, + "process-warning": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz", + "integrity": "sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==" + }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -31780,6 +33532,12 @@ "react-is": "^16.13.1" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -31789,6 +33547,15 @@ "ipaddr.js": "1.9.1" } }, + "ps-node": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ps-node/-/ps-node-0.1.6.tgz", + "integrity": "sha512-w7QJhUTbu70hpDso0YXDRNKCPNuchV8UTUZsAv0m7Qj5g85oHOJfr9drA1EjvK4nQK/bG8P97W4L6PJ3IQLoOA==", + "dev": true, + "requires": { + "table-parser": "^0.1.3" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -32166,16 +33933,16 @@ } }, "redis": { - "version": "4.6.11", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.11.tgz", - "integrity": "sha512-kg1Lt4NZLYkAjPOj/WcyIGWfZfnyfKo1Wg9YKVSlzhFwxpFIl3LYI8BWy1Ab963LLDsTz2+OwdsesHKljB3WMQ==", + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz", + "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==", "requires": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.12", - "@redis/graph": "1.1.1", - "@redis/json": "1.0.6", - "@redis/search": "1.1.6", - "@redis/time-series": "1.0.5" + "@redis/client": "1.5.7", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" } }, "regenerate": { @@ -32387,6 +34154,36 @@ } } }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "dev": true, + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + }, + "dependencies": { + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "require-at": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "dev": true + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -32559,6 +34356,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "sass-lookup": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/sass-lookup/-/sass-lookup-3.0.0.tgz", @@ -32756,9 +34562,9 @@ } }, "semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "requires": { "lru-cache": "^6.0.0" }, @@ -33143,6 +34949,24 @@ "smart-buffer": "^4.2.0" } }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "requires": { + "sort-keys": "^1.0.0" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -33490,6 +35314,15 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "stylus-lookup": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stylus-lookup/-/stylus-lookup-3.0.2.tgz", @@ -33580,6 +35413,15 @@ "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true }, + "table-parser": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/table-parser/-/table-parser-0.1.3.tgz", + "integrity": "sha512-LCYeuvqqoPII3lzzYaXKbC3Forb+d2u4bNwhk/9FlivuGRxPE28YEWAYcujeSlLLDlMfvy29+WPybFJZFiKMYg==", + "dev": true, + "requires": { + "connected-domain": "^1.0.0" + } + }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", @@ -33592,28 +35434,6 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, - "tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -33729,6 +35549,18 @@ } } }, + "tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true + }, "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -33907,6 +35739,15 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -34188,6 +36029,12 @@ } } }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, "upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -34238,6 +36085,21 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==", + "dev": true + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -34252,6 +36114,12 @@ "dev": true, "requires": {} }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -34455,9 +36323,9 @@ } }, "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, "wordwrap": { "version": "1.0.0", @@ -34520,9 +36388,9 @@ } }, "ws": { - "version": "8.15.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", - "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "requires": {} }, "xmlcreate": { diff --git a/package.json b/package.json index b0c278f845..2d6914cb99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-server", - "version": "7.0.0-alpha.19", + "version": "6.3.0-beta.1", "description": "An express module providing a Parse-compatible API server", "main": "lib/index.js", "repository": { @@ -24,8 +24,8 @@ "@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.0.2", + "@parse/fs-files-adapter": "1.2.2", + "@parse/push-adapter": "4.1.3", "bcryptjs": "2.4.3", "body-parser": "1.20.2", "commander": "10.0.1", @@ -33,35 +33,35 @@ "deepcopy": "2.1.0", "express": "4.18.2", "express-rate-limit": "6.7.0", - "follow-redirects": "1.15.4", - "graphql": "16.8.1", + "follow-redirects": "1.15.2", + "graphql": "16.6.0", "graphql-list-fields": "2.0.2", "graphql-relay": "0.10.0", "graphql-tag": "2.12.6", "intersect": "1.0.1", + "ip-range-check": "0.2.0", "jsonwebtoken": "9.0.0", - "jwks-rsa": "3.1.0", - "ldapjs": "2.3.3", + "jwks-rsa": "2.1.5", + "ldapjs": "3.0.2", "lodash": "4.17.21", - "lru-cache": "10.1.0", + "lru-cache": "9.1.1", "mime": "3.0.0", - "mongodb": "5.9.0", + "mongodb": "4.10.0", "mustache": "4.2.0", - "otpauth": "9.2.1", "parse": "4.1.0", "path-to-regexp": "6.2.1", "pg-monitor": "2.0.0", - "pg-promise": "11.5.4", + "pg-promise": "11.5.0", "pluralize": "8.0.0", "rate-limit-redis": "3.0.2", - "redis": "4.6.11", - "semver": "7.5.2", + "redis": "4.6.6", + "semver": "7.5.1", "subscriptions-transport-ws": "0.11.0", "tv4": "1.3.0", "uuid": "9.0.0", "winston": "3.8.2", "winston-daily-rotate-file": "4.7.1", - "ws": "8.15.1" + "ws": "8.13.0" }, "devDependencies": { "@actions/core": "1.9.1", @@ -80,6 +80,7 @@ "@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", "deep-diff": "1.0.2", @@ -97,7 +98,7 @@ "madge": "5.0.1", "mock-files-adapter": "file:spec/dependencies/mock-files-adapter", "mock-mail-adapter": "file:spec/dependencies/mock-mail-adapter", - "mongodb-runner": "5.4.4", + "mongodb-runner": "4.8.1", "mongodb-version-list": "1.0.0", "node-abort-controller": "3.0.1", "node-fetch": "3.2.10", @@ -116,18 +117,18 @@ "lint-fix": "eslint --fix --cache ./", "build": "babel src/ -d lib/ --copy-files", "watch": "babel --watch src/ -d lib/ --copy-files", - "test:mongodb:runnerstart": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=$npm_config_dbversion} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017", + "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", - "test:mongodb:7.0.1": "npm run test:mongodb --dbversion=7.0.1", - "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017", + "posttest:mongodb": "mongodb-runner stop", + "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.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-runner stop --all", + "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", "start": "node ./bin/parse-server", "prettier": "prettier --write {src,spec}/{**/*,*}.js", @@ -136,7 +137,7 @@ "madge:circular": "node_modules/.bin/madge ./src --circular" }, "engines": { - "node": ">=18.0.0 <21" + "node": ">=14.21.0 <17 || >=18 <19" }, "bin": { "parse-server": "bin/parse-server" diff --git a/postinstall.js b/postinstall.js index fe1fc96bae..fef1fb31ff 100644 --- a/postinstall.js +++ b/postinstall.js @@ -1,6 +1,6 @@ const pkg = require('./package.json'); -const version = parseFloat(process.version.substring(1)); +const version = parseFloat(process.version.substr(1)); const minimum = parseFloat(pkg.engines.node.match(/\d+/g).join('.')); module.exports = function () { diff --git a/release.config.js b/release.config.js index 67d62c56c6..b3776e2320 100644 --- a/release.config.js +++ b/release.config.js @@ -40,8 +40,8 @@ async function config() { { name: 'alpha', prerelease: true }, { name: 'beta', prerelease: true }, 'next-major', - // Long-Term-Support branch of previous major version - 'release-6.x.x', + // Long-Term-Support branches; defined as GLOB pattern + 'release-+([0-9]).x.x', ], dryRun: false, debug: true, diff --git a/release_docs.sh b/release_docs.sh index a9cc5bf3bc..a7bb26324c 100755 --- a/release_docs.sh +++ b/release_docs.sh @@ -27,8 +27,3 @@ npm run docs mkdir -p "docs/api/${DEST}" cp -R out/* "docs/api/${DEST}" - -# Copy other resources -RESOURCE_DIR=".github" -mkdir -p "docs/${RESOURCE_DIR}" -cp "./.github/parse-server-logo.png" "docs/${RESOURCE_DIR}/" diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index 0be6e0085d..e0d33daa4b 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -255,16 +255,7 @@ function inject(t, list) { props.push(t.objectProperty(t.stringLiteral('action'), action)); } if (elt.defaultValue) { - let parsedValue = parseDefaultValue(elt, elt.defaultValue, t); - if (!parsedValue) { - for (const type of elt.typeAnnotation.types) { - elt.type = type.type; - parsedValue = parseDefaultValue(elt, elt.defaultValue, t); - if (parsedValue) { - break; - } - } - } + const parsedValue = parseDefaultValue(elt, elt.defaultValue, t); if (parsedValue) { props.push(t.objectProperty(t.stringLiteral('default'), parsedValue)); } else { diff --git a/spec/.eslintrc.json b/spec/.eslintrc.json index cb61d2fd6c..8f8bcfeddc 100644 --- a/spec/.eslintrc.json +++ b/spec/.eslintrc.json @@ -15,7 +15,6 @@ "equal": true, "expectAsync": true, "notEqual": true, - "it_id": true, "it_only_db": true, "it_only_mongodb_version": true, "it_only_postgres_version": true, @@ -28,7 +27,6 @@ "fit_exclude_node_version": true, "it_exclude_dbs": true, "describe_only_db": true, - "fdescribe_only_db": true, "describe_only": true, "on_db": true, "defaultConfiguration": true, diff --git a/spec/AudienceRouter.spec.js b/spec/AudienceRouter.spec.js index f2302d32f7..9f0f77896a 100644 --- a/spec/AudienceRouter.spec.js +++ b/spec/AudienceRouter.spec.js @@ -339,12 +339,11 @@ describe('AudiencesRouter', () => { ) .then(result => { expect(result).toBeTruthy(); - database .collection('test__Audience') .find({ _id: audience.objectId }) - .toArray() - .then(rows => { + .toArray((error, rows) => { + expect(error).toEqual(undefined); expect(rows[0]['times_used']).toEqual(1); expect(rows[0]['_last_used']).toEqual(now); Parse._request( @@ -363,9 +362,6 @@ describe('AudiencesRouter', () => { .catch(error => { done.fail(error); }); - }) - .catch(error => { - done.fail(error); }); }); }); diff --git a/spec/Auth.spec.js b/spec/Auth.spec.js index 632623a871..26421487df 100644 --- a/spec/Auth.spec.js +++ b/spec/Auth.spec.js @@ -81,6 +81,17 @@ 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 () => { diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index c6834dcf45..bb89596cef 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -589,6 +589,20 @@ describe('AuthenticationProviders', function () { new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE, 'This authentication method is unsupported.') ); }); + + it('can deprecate', async () => { + await reconfigureServer(); + const Deprecator = require('../lib/Deprecator/Deprecator'); + const spy = spyOn(Deprecator, 'logRuntimeDeprecation').and.callFake(() => {}); + const provider = getMockMyOauthProvider(); + Parse.User._registerAuthenticationProvider(provider); + await Parse.User._logInWith('myoauth'); + expect(spy).toHaveBeenCalledWith({ + usage: 'Using the authentication adapter "myoauth" without explicitly enabling it', + solution: + 'Enable the authentication adapter by setting the Parse Server option "auth.myoauth.enabled: true".', + }); + }); }); describe('instagram auth adapter', () => { @@ -1440,6 +1454,7 @@ describe('oauth2 auth adapter', () => { describe('apple signin auth adapter', () => { const apple = require('../lib/Adapters/Auth/apple'); const jwt = require('jsonwebtoken'); + const util = require('util'); const authUtils = require('../lib/Adapters/Auth/utils'); it('(using client id as string) should throw error with missing id_token', async () => { @@ -1497,10 +1512,12 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken.header); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); const result = await apple.validateAuthData( { id: 'the_user_id', token: 'the_token' }, @@ -1512,9 +1529,11 @@ describe('apple signin auth adapter', () => { it('should not verify invalid id_token', async () => { const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); try { await apple.validateAuthData( @@ -1547,9 +1566,11 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await apple.validateAuthData( @@ -1567,9 +1588,11 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await apple.validateAuthData( @@ -1587,9 +1610,11 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await apple.validateAuthData( @@ -1605,9 +1630,11 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1631,9 +1658,11 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1658,9 +1687,11 @@ describe('apple signin auth adapter', () => { sub: 'the_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1728,9 +1759,11 @@ describe('apple signin auth adapter', () => { sub: 'a_different_user_id', }; const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1992,6 +2025,7 @@ describe('microsoft graph auth adapter', () => { describe('facebook limited auth adapter', () => { const facebook = require('../lib/Adapters/Auth/facebook'); const jwt = require('jsonwebtoken'); + const util = require('util'); const authUtils = require('../lib/Adapters/Auth/utils'); // TODO: figure out a way to run this test alongside facebook classic tests @@ -2052,11 +2086,18 @@ describe('facebook limited auth adapter', () => { exp: Date.now(), sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken.header); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); const result = await facebook.validateAuthData( { id: 'the_user_id', token: 'the_token' }, @@ -2067,10 +2108,17 @@ describe('facebook limited auth adapter', () => { }); it('should not verify invalid id_token', async () => { - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); try { await facebook.validateAuthData( @@ -2102,10 +2150,17 @@ describe('facebook limited auth adapter', () => { exp: Date.now(), sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await facebook.validateAuthData( @@ -2122,10 +2177,17 @@ describe('facebook limited auth adapter', () => { exp: Date.now(), sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await facebook.validateAuthData( @@ -2142,10 +2204,17 @@ describe('facebook limited auth adapter', () => { exp: Date.now(), sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await facebook.validateAuthData( @@ -2160,10 +2229,17 @@ describe('facebook limited auth adapter', () => { iss: 'https://not.facebook.com', sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2186,10 +2262,17 @@ describe('facebook limited auth adapter', () => { iss: 'https://not.facebook.com', sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2213,10 +2296,17 @@ describe('facebook limited auth adapter', () => { iss: 'https://not.facebook.com', sub: 'the_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2292,10 +2382,17 @@ describe('facebook limited auth adapter', () => { aud: 'invalid_client_id', sub: 'a_different_user_id', }; - const fakeDecodedToken = { header: { kid: '123', alg: 'RS256' } }; - const fakeSigningKey = { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; + const fakeDecodedToken = { + header: { kid: '123', alg: 'RS256' }, + }; spyOn(authUtils, 'getHeaderFromToken').and.callFake(() => fakeDecodedToken); - spyOn(authUtils, 'getSigningKey').and.resolveTo(fakeSigningKey); + const fakeGetSigningKeyAsyncFunction = () => { + return { + kid: '123', + rsaPublicKey: 'the_rsa_public_key', + }; + }; + spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2309,342 +2406,3 @@ describe('facebook limited auth adapter', () => { } }); }); - -describe('OTP TOTP auth adatper', () => { - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - }; - beforeEach(async () => { - await reconfigureServer({ - auth: { - mfa: { - enabled: true, - options: ['TOTP'], - algorithm: 'SHA1', - digits: 6, - period: 30, - }, - }, - }); - }); - - it('can enroll', async () => { - const user = await Parse.User.signUp('username', 'password'); - const OTPAuth = require('otpauth'); - const secret = new OTPAuth.Secret(); - const totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret, - }); - const token = totp.generate(); - await user.save( - { authData: { mfa: { secret: secret.base32, token } } }, - { sessionToken: user.getSessionToken() } - ); - const response = user.get('authDataResponse'); - expect(response.mfa).toBeDefined(); - expect(response.mfa.recovery).toBeDefined(); - expect(response.mfa.recovery.split(',').length).toEqual(2); - await user.fetch(); - expect(user.get('authData').mfa).toEqual({ status: 'enabled' }); - }); - - it('can login with valid token', async () => { - const user = await Parse.User.signUp('username', 'password'); - const OTPAuth = require('otpauth'); - const secret = new OTPAuth.Secret(); - const totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret, - }); - const token = totp.generate(); - await user.save( - { authData: { mfa: { secret: secret.base32, token } } }, - { sessionToken: user.getSessionToken() } - ); - const response = await request({ - headers, - method: 'POST', - url: 'http://localhost:8378/1/login', - body: JSON.stringify({ - username: 'username', - password: 'password', - authData: { - mfa: { - token: totp.generate(), - }, - }, - }), - }).then(res => res.data); - expect(response.objectId).toEqual(user.id); - expect(response.sessionToken).toBeDefined(); - expect(response.authData).toEqual({ mfa: { status: 'enabled' } }); - expect(Object.keys(response).sort()).toEqual( - [ - 'objectId', - 'username', - 'createdAt', - 'updatedAt', - 'authData', - 'ACL', - 'sessionToken', - 'authDataResponse', - ].sort() - ); - }); - - it('can change OTP with valid token', async () => { - const user = await Parse.User.signUp('username', 'password'); - const OTPAuth = require('otpauth'); - const secret = new OTPAuth.Secret(); - const totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret, - }); - const token = totp.generate(); - await user.save( - { authData: { mfa: { secret: secret.base32, token } } }, - { sessionToken: user.getSessionToken() } - ); - - const new_secret = new OTPAuth.Secret(); - const new_totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret: new_secret, - }); - const new_token = new_totp.generate(); - await user.save( - { - authData: { mfa: { secret: new_secret.base32, token: new_token, old: totp.generate() } }, - }, - { sessionToken: user.getSessionToken() } - ); - await user.fetch({ useMasterKey: true }); - expect(user.get('authData').mfa.secret).toEqual(new_secret.base32); - }); - - it('cannot change OTP with invalid token', async () => { - const user = await Parse.User.signUp('username', 'password'); - const OTPAuth = require('otpauth'); - const secret = new OTPAuth.Secret(); - const totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret, - }); - const token = totp.generate(); - await user.save( - { authData: { mfa: { secret: secret.base32, token } } }, - { sessionToken: user.getSessionToken() } - ); - - const new_secret = new OTPAuth.Secret(); - const new_totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret: new_secret, - }); - const new_token = new_totp.generate(); - await expectAsync( - user.save( - { - authData: { mfa: { secret: new_secret.base32, token: new_token, old: '123' } }, - }, - { sessionToken: user.getSessionToken() } - ) - ).toBeRejectedWith(new Parse.Error(Parse.Error.OTHER_CAUSE, 'Invalid MFA token')); - await user.fetch({ useMasterKey: true }); - expect(user.get('authData').mfa.secret).toEqual(secret.base32); - }); - - it('future logins require TOTP token', async () => { - const user = await Parse.User.signUp('username', 'password'); - const OTPAuth = require('otpauth'); - const secret = new OTPAuth.Secret(); - const totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret, - }); - const token = totp.generate(); - await user.save( - { authData: { mfa: { secret: secret.base32, token } } }, - { sessionToken: user.getSessionToken() } - ); - await expectAsync(Parse.User.logIn('username', 'password')).toBeRejectedWith( - new Parse.Error(Parse.Error.OTHER_CAUSE, 'Missing additional authData mfa') - ); - }); - - it('future logins reject incorrect TOTP token', async () => { - const user = await Parse.User.signUp('username', 'password'); - const OTPAuth = require('otpauth'); - const secret = new OTPAuth.Secret(); - const totp = new OTPAuth.TOTP({ - algorithm: 'SHA1', - digits: 6, - period: 30, - secret, - }); - const token = totp.generate(); - await user.save( - { authData: { mfa: { secret: secret.base32, token } } }, - { sessionToken: user.getSessionToken() } - ); - await expectAsync( - request({ - headers, - method: 'POST', - url: 'http://localhost:8378/1/login', - body: JSON.stringify({ - username: 'username', - password: 'password', - authData: { - mfa: { - token: 'abcd', - }, - }, - }), - }).catch(e => { - throw e.data; - }) - ).toBeRejectedWith({ code: Parse.Error.SCRIPT_FAILED, error: 'Invalid MFA token' }); - }); -}); - -describe('OTP SMS auth adatper', () => { - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - }; - let code; - let mobile; - const mfa = { - enabled: true, - options: ['SMS'], - sendSMS(smsCode, number) { - expect(smsCode).toBeDefined(); - expect(number).toBeDefined(); - expect(smsCode.length).toEqual(6); - code = smsCode; - mobile = number; - }, - digits: 6, - period: 30, - }; - beforeEach(async () => { - code = ''; - mobile = ''; - await reconfigureServer({ - auth: { - mfa, - }, - }); - }); - - it('can enroll', async () => { - const user = await Parse.User.signUp('username', 'password'); - const sessionToken = user.getSessionToken(); - const spy = spyOn(mfa, 'sendSMS').and.callThrough(); - await user.save({ authData: { mfa: { mobile: '+11111111111' } } }, { sessionToken }); - await user.fetch({ sessionToken }); - expect(user.get('authData')).toEqual({ mfa: { status: 'disabled' } }); - expect(spy).toHaveBeenCalledWith(code, '+11111111111'); - await user.fetch({ useMasterKey: true }); - const authData = user.get('authData').mfa?.pending; - expect(authData).toBeDefined(); - expect(authData['+11111111111']).toBeDefined(); - expect(Object.keys(authData['+11111111111'])).toEqual(['token', 'expiry']); - - await user.save({ authData: { mfa: { mobile, token: code } } }, { sessionToken }); - await user.fetch({ sessionToken }); - expect(user.get('authData')).toEqual({ mfa: { status: 'enabled' } }); - }); - - it('future logins require SMS code', async () => { - const user = await Parse.User.signUp('username', 'password'); - const spy = spyOn(mfa, 'sendSMS').and.callThrough(); - await user.save( - { authData: { mfa: { mobile: '+11111111111' } } }, - { sessionToken: user.getSessionToken() } - ); - - await user.save( - { authData: { mfa: { mobile, token: code } } }, - { sessionToken: user.getSessionToken() } - ); - - spy.calls.reset(); - - await expectAsync(Parse.User.logIn('username', 'password')).toBeRejectedWith( - new Parse.Error(Parse.Error.OTHER_CAUSE, 'Missing additional authData mfa') - ); - const res = await request({ - headers, - method: 'POST', - url: 'http://localhost:8378/1/login', - body: JSON.stringify({ - username: 'username', - password: 'password', - authData: { - mfa: { - token: 'request', - }, - }, - }), - }).catch(e => e.data); - expect(res).toEqual({ code: Parse.Error.SCRIPT_FAILED, error: 'Please enter the token' }); - expect(spy).toHaveBeenCalledWith(code, '+11111111111'); - const response = await request({ - headers, - method: 'POST', - url: 'http://localhost:8378/1/login', - body: JSON.stringify({ - username: 'username', - password: 'password', - authData: { - mfa: { - token: code, - }, - }, - }), - }).then(res => res.data); - expect(response.objectId).toEqual(user.id); - expect(response.sessionToken).toBeDefined(); - expect(response.authData).toEqual({ mfa: { status: 'enabled' } }); - expect(Object.keys(response).sort()).toEqual( - [ - 'objectId', - 'username', - 'createdAt', - 'updatedAt', - 'authData', - 'ACL', - 'sessionToken', - 'authDataResponse', - ].sort() - ); - }); - - it('partially enrolled users can still login', async () => { - const user = await Parse.User.signUp('username', 'password'); - await user.save({ authData: { mfa: { mobile: '+11111111111' } } }); - const spy = spyOn(mfa, 'sendSMS').and.callThrough(); - await Parse.User.logIn('username', 'password'); - expect(spy).not.toHaveBeenCalled(); - }); -}); diff --git a/spec/CLI.spec.js b/spec/CLI.spec.js index d73b854a9b..20667fd349 100644 --- a/spec/CLI.spec.js +++ b/spec/CLI.spec.js @@ -302,25 +302,4 @@ describe('execution', () => { done.fail(data.toString()); }); }); - - it('can start Parse Server with auth via CLI', done => { - const env = { ...process.env }; - env.NODE_OPTIONS = '--dns-result-order=ipv4first'; - childProcess = spawn( - binPath, - ['--databaseURI', databaseURI, './spec/configs/CLIConfigAuth.json'], - { env } - ); - childProcess.stdout.on('data', data => { - data = data.toString(); - console.log(data); - if (data.includes('parse-server running on')) { - done(); - } - }); - childProcess.stderr.on('data', data => { - data = data.toString(); - done.fail(data.toString()); - }); - }); }); diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 239a58d39f..a8795a4e84 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -103,14 +103,6 @@ describe('Cloud Code', () => { expect(currentConfig.silent).toBeFalse(); }); - it('can get curent version', () => { - const version = require('../package.json').version; - const currentConfig = Config.get('test'); - expect(Parse.Server.version).toBeDefined(); - expect(currentConfig.version).toBeDefined(); - expect(Parse.Server.version).toEqual(version); - }); - it('show warning on duplicate cloud functions', done => { const logger = require('../lib/logger').logger; spyOn(logger, 'warn').and.callFake(() => {}); @@ -1361,27 +1353,7 @@ describe('Cloud Code', () => { }); }); - it('should not encode Parse Objects', async () => { - const user = new Parse.User(); - user.setUsername('username'); - user.setPassword('password'); - user.set('deleted', false); - await user.signUp(); - Parse.Cloud.define( - 'deleteAccount', - async req => { - expect(req.params.object instanceof Parse.Object).not.toBeTrue(); - return 'Object deleted'; - }, - { - requireMaster: true, - } - ); - await Parse.Cloud.run('deleteAccount', { object: user.toPointer() }, { useMasterKey: true }); - }); - it('allow cloud to encode Parse Objects', async () => { - await reconfigureServer({ encodeParseObjectInCloudFunction: true }); const user = new Parse.User(); user.setUsername('username'); user.setPassword('password'); @@ -2398,56 +2370,6 @@ describe('beforeFind hooks', () => { }); }); - it('sets correct beforeFind trigger isGet parameter for Parse.Object.fetch request', async () => { - const hook = { - method: req => { - expect(req.isGet).toEqual(true); - return Promise.resolve(); - }, - }; - spyOn(hook, 'method').and.callThrough(); - Parse.Cloud.beforeFind('MyObject', hook.method); - const obj = new Parse.Object('MyObject'); - await obj.save(); - const getObj = await obj.fetch(); - expect(getObj).toBeInstanceOf(Parse.Object); - expect(hook.method).toHaveBeenCalledTimes(1); - }); - - it('sets correct beforeFind trigger isGet parameter for Parse.Query.get request', async () => { - const hook = { - method: req => { - expect(req.isGet).toEqual(false); - return Promise.resolve(); - }, - }; - spyOn(hook, 'method').and.callThrough(); - Parse.Cloud.beforeFind('MyObject', hook.method); - const obj = new Parse.Object('MyObject'); - await obj.save(); - const query = new Parse.Query('MyObject'); - const getObj = await query.get(obj.id); - expect(getObj).toBeInstanceOf(Parse.Object); - expect(hook.method).toHaveBeenCalledTimes(1); - }); - - it('sets correct beforeFind trigger isGet parameter for Parse.Query.find request', async () => { - const hook = { - method: req => { - expect(req.isGet).toEqual(false); - return Promise.resolve(); - }, - }; - spyOn(hook, 'method').and.callThrough(); - Parse.Cloud.beforeFind('MyObject', hook.method); - const obj = new Parse.Object('MyObject'); - await obj.save(); - const query = new Parse.Query('MyObject'); - const findObjs = await query.find(); - expect(findObjs?.[0]).toBeInstanceOf(Parse.Object); - expect(hook.method).toHaveBeenCalledTimes(1); - }); - it('should have request headers', done => { Parse.Cloud.beforeFind('MyObject', req => { expect(req.headers).toBeDefined(); @@ -2481,60 +2403,6 @@ describe('beforeFind hooks', () => { }) .then(() => done()); }); - - it('should run beforeFind on pointers and array of pointers from an object', async () => { - const obj1 = new Parse.Object('TestObject'); - const obj2 = new Parse.Object('TestObject2'); - const obj3 = new Parse.Object('TestObject'); - obj2.set('aField', 'aFieldValue'); - await obj2.save(); - obj1.set('pointerField', obj2); - obj3.set('pointerFieldArray', [obj2]); - await obj1.save(); - await obj3.save(); - const spy = jasmine.createSpy('beforeFindSpy'); - Parse.Cloud.beforeFind('TestObject2', spy); - const query = new Parse.Query('TestObject'); - await query.get(obj1.id); - // Pointer not included in query so we don't expect beforeFind to be called - expect(spy).not.toHaveBeenCalled(); - const query2 = new Parse.Query('TestObject'); - query2.include('pointerField'); - const res = await query2.get(obj1.id); - expect(res.get('pointerField').get('aField')).toBe('aFieldValue'); - // Pointer included in query so we expect beforeFind to be called - expect(spy).toHaveBeenCalledTimes(1); - const query3 = new Parse.Query('TestObject'); - query3.include('pointerFieldArray'); - const res2 = await query3.get(obj3.id); - expect(res2.get('pointerFieldArray')[0].get('aField')).toBe('aFieldValue'); - expect(spy).toHaveBeenCalledTimes(2); - }); - - it('should have access to context in include query in beforeFind hook', async () => { - let beforeFindTestObjectCalled = false; - let beforeFindTestObject2Called = false; - const obj1 = new Parse.Object('TestObject'); - const obj2 = new Parse.Object('TestObject2'); - obj2.set('aField', 'aFieldValue'); - await obj2.save(); - obj1.set('pointerField', obj2); - await obj1.save(); - Parse.Cloud.beforeFind('TestObject', req => { - expect(req.context).toBeDefined(); - expect(req.context.a).toEqual('a'); - beforeFindTestObjectCalled = true; - }); - Parse.Cloud.beforeFind('TestObject2', req => { - expect(req.context).toBeDefined(); - expect(req.context.a).toEqual('a'); - beforeFindTestObject2Called = true; - }); - const query = new Parse.Query('TestObject'); - await query.include('pointerField').find({ context: { a: 'a' } }); - expect(beforeFindTestObjectCalled).toBeTrue(); - expect(beforeFindTestObject2Called).toBeTrue(); - }); }); describe('afterFind hooks', () => { @@ -3352,7 +3220,7 @@ describe('beforeLogin hook', () => { expect(req.headers).toBeDefined(); expect(req.ip).toBeDefined(); expect(req.installationId).toBeDefined(); - expect(req.context).toBeDefined(); + expect(req.context).toBeUndefined(); }); await Parse.User.signUp('tupac', 'shakur'); @@ -3469,7 +3337,7 @@ describe('afterLogin hook', () => { expect(req.headers).toBeDefined(); expect(req.ip).toBeDefined(); expect(req.installationId).toBeDefined(); - expect(req.context).toBeDefined(); + expect(req.context).toBeUndefined(); }); await Parse.User.signUp('testuser', 'p@ssword'); @@ -3635,7 +3503,7 @@ describe('afterLogin hook', () => { }); describe('saveFile hooks', () => { - it('beforeSave(Parse.File) should return file that is already saved and not save anything to files adapter', async () => { + it('beforeSaveFile should return file that is already saved and not save anything to files adapter', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, () => { @@ -3651,7 +3519,7 @@ describe('saveFile hooks', () => { expect(createFileSpy).not.toHaveBeenCalled(); }); - it('beforeSave(Parse.File) should throw error', async () => { + it('beforeSaveFile should throw error', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, () => { throw new Parse.Error(400, 'some-error-message'); @@ -3664,7 +3532,7 @@ describe('saveFile hooks', () => { } }); - it('beforeSave(Parse.File) should change values of uploaded file by editing fileObject directly', async () => { + it('beforeSaveFile should change values of uploaded file by editing fileObject directly', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, async req => { @@ -3693,7 +3561,7 @@ describe('saveFile hooks', () => { ); }); - it('beforeSave(Parse.File) should change values by returning new fileObject', async () => { + it('beforeSaveFile should change values by returning new fileObject', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, async req => { @@ -3727,7 +3595,7 @@ describe('saveFile hooks', () => { expect(file._name.indexOf(expectedFileName)).toBe(file._name.length - expectedFileName.length); }); - it('beforeSave(Parse.File) should contain metadata and tags saved from client', async () => { + it('beforeSaveFile should contain metadata and tags saved from client', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, async req => { @@ -3755,7 +3623,7 @@ describe('saveFile hooks', () => { ); }); - it('beforeSave(Parse.File) should return same file data with new file name', async () => { + it('beforeSaveFile should return same file data with new file name', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const config = Config.get('test'); config.filesController.options.preserveFileName = true; @@ -3770,7 +3638,7 @@ describe('saveFile hooks', () => { expect(result.name()).toBe('2020-04-01.txt'); }); - it('afterSave(Parse.File) should set fileSize to null if beforeSave returns an already saved file', async () => { + it('afterSaveFile should set fileSize to null if beforeSave returns an already saved file', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, req => { @@ -3790,7 +3658,7 @@ describe('saveFile hooks', () => { expect(createFileSpy).not.toHaveBeenCalled(); }); - it('afterSave(Parse.File) should throw error', async () => { + it('afterSaveFile should throw error', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.afterSave(Parse.File, async () => { throw new Parse.Error(400, 'some-error-message'); @@ -3804,7 +3672,7 @@ describe('saveFile hooks', () => { } }); - it('afterSave(Parse.File) should call with fileObject', async done => { + it('afterSaveFile should call with fileObject', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, async req => { req.file.setTags({ tagA: 'some-tag' }); @@ -3820,7 +3688,7 @@ describe('saveFile hooks', () => { await file.save({ useMasterKey: true }); }); - it('afterSave(Parse.File) should change fileSize when file data changes', async done => { + it('afterSaveFile should change fileSize when file data changes', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, async req => { expect(req.fileSize).toBe(3); @@ -3837,7 +3705,7 @@ describe('saveFile hooks', () => { await file.save({ useMasterKey: true }); }); - it('beforeDelete(Parse.File) should call with fileObject', async () => { + it('beforeDeleteFile should call with fileObject', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeDelete(Parse.File, req => { expect(req.file).toBeInstanceOf(Parse.File); @@ -3849,7 +3717,7 @@ describe('saveFile hooks', () => { await file.destroy({ useMasterKey: true }); }); - it('beforeDelete(Parse.File) should throw error', async done => { + it('beforeDeleteFile should throw error', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeDelete(Parse.File, () => { throw new Error('some error message'); @@ -3863,7 +3731,7 @@ describe('saveFile hooks', () => { } }); - it('afterDelete(Parse.File) should call with fileObject', async done => { + it('afterDeleteFile should call with fileObject', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeDelete(Parse.File, req => { expect(req.file).toBeInstanceOf(Parse.File); @@ -3880,7 +3748,7 @@ describe('saveFile hooks', () => { await file.destroy({ useMasterKey: true }); }); - it('beforeSave(Parse.File) should not change file if nothing is returned', async () => { + it('beforeSaveFile should not change file if nothing is returned', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, () => { return; @@ -3890,7 +3758,7 @@ describe('saveFile hooks', () => { expect(result).toBe(file); }); - it('throw custom error from beforeSave(Parse.File) ', async done => { + it('throw custom error from beforeSaveFile', async done => { Parse.Cloud.beforeSave(Parse.File, () => { throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'It should fail'); }); @@ -3904,7 +3772,7 @@ describe('saveFile hooks', () => { } }); - it('throw empty error from beforeSave(Parse.File)', async done => { + it('throw empty error from beforeSaveFile', async done => { Parse.Cloud.beforeSave(Parse.File, () => { throw null; }); @@ -3917,6 +3785,55 @@ describe('saveFile hooks', () => { done(); } }); + + it('legacy hooks', async () => { + await reconfigureServer({ filesAdapter: mockAdapter }); + const logger = require('../lib/logger').logger; + const logSpy = spyOn(logger, 'warn').and.callFake(() => {}); + const triggers = { + beforeSaveFile(req) { + req.file.setTags({ tagA: 'some-tag' }); + req.file.setMetadata({ foo: 'bar' }); + expect(req.triggerName).toEqual('beforeSave'); + expect(req.master).toBe(true); + }, + afterSaveFile(req) { + expect(req.master).toBe(true); + expect(req.file._tags).toEqual({ tagA: 'some-tag' }); + expect(req.file._metadata).toEqual({ foo: 'bar' }); + }, + beforeDeleteFile(req) { + expect(req.file).toBeInstanceOf(Parse.File); + expect(req.file._name).toEqual('popeye.txt'); + expect(req.file._url).toEqual('http://www.somewhere.com/popeye.txt'); + expect(req.fileSize).toBe(null); + }, + afterDeleteFile(req) { + expect(req.file).toBeInstanceOf(Parse.File); + expect(req.file._name).toEqual('popeye.txt'); + expect(req.file._url).toEqual('http://www.somewhere.com/popeye.txt'); + }, + }; + + for (const key in triggers) { + spyOn(triggers, key).and.callThrough(); + Parse.Cloud[key](triggers[key]); + } + + const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain'); + await file.save({ useMasterKey: true }); + await new Parse.File('popeye.txt', [1, 2, 3], 'text/plain').destroy({ useMasterKey: true }); + await new Promise(resolve => setTimeout(resolve, 100)); + for (const key in triggers) { + expect(triggers[key]).toHaveBeenCalled(); + expect(logSpy).toHaveBeenCalledWith( + `DeprecationWarning: Parse.Cloud.${key} is deprecated and will be removed in a future version. Use Parse.Cloud.${key.replace( + 'File', + '' + )}(Parse.File, (request) => {})` + ); + } + }); }); describe('sendEmail', () => { diff --git a/spec/DatabaseController.spec.js b/spec/DatabaseController.spec.js index e1b50a5a52..98103ce6e4 100644 --- a/spec/DatabaseController.spec.js +++ b/spec/DatabaseController.spec.js @@ -1,4 +1,3 @@ -const Config = require('../lib/Config'); const DatabaseController = require('../lib/Controllers/DatabaseController.js'); const validateQuery = DatabaseController._validateQuery; @@ -362,259 +361,6 @@ describe('DatabaseController', function () { done(); }); }); - - describe('enableCollationCaseComparison', () => { - const dummyStorageAdapter = { - find: () => Promise.resolve([]), - watch: () => Promise.resolve(), - getAllClasses: () => Promise.resolve([]), - }; - - beforeEach(() => { - Config.get(Parse.applicationId).schemaCache.clear(); - }); - - it('should force caseInsensitive to false with enableCollationCaseComparison option', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, { - enableCollationCaseComparison: true, - }); - const spy = spyOn(dummyStorageAdapter, 'find'); - spy.and.callThrough(); - await databaseController.find('SomeClass', {}, { caseInsensitive: true }); - expect(spy.calls.all()[0].args[3].caseInsensitive).toEqual(false); - }); - - it('should support caseInsensitive without enableCollationCaseComparison option', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, {}); - const spy = spyOn(dummyStorageAdapter, 'find'); - spy.and.callThrough(); - await databaseController.find('_User', {}, { caseInsensitive: true }); - expect(spy.calls.all()[0].args[3].caseInsensitive).toEqual(true); - }); - - it_only_db('mongo')( - 'should create insensitive indexes without enableCollationCaseComparison', - async () => { - await reconfigureServer({ - databaseURI: 'mongodb://localhost:27017/enableCollationCaseComparisonFalse', - databaseAdapter: undefined, - }); - const user = new Parse.User(); - await user.save({ - username: 'example', - password: 'password', - email: 'example@example.com', - }); - const schemas = await Parse.Schema.all(); - const UserSchema = schemas.find(({ className }) => className === '_User'); - expect(UserSchema.indexes).toEqual({ - _id_: { _id: 1 }, - username_1: { username: 1 }, - case_insensitive_username: { username: 1 }, - case_insensitive_email: { email: 1 }, - email_1: { email: 1 }, - }); - } - ); - - it_only_db('mongo')( - 'should not create insensitive indexes with enableCollationCaseComparison', - async () => { - await reconfigureServer({ - enableCollationCaseComparison: true, - databaseURI: 'mongodb://localhost:27017/enableCollationCaseComparisonTrue', - databaseAdapter: undefined, - }); - const user = new Parse.User(); - await user.save({ - username: 'example', - password: 'password', - email: 'example@example.com', - }); - const schemas = await Parse.Schema.all(); - const UserSchema = schemas.find(({ className }) => className === '_User'); - expect(UserSchema.indexes).toEqual({ - _id_: { _id: 1 }, - username_1: { username: 1 }, - email_1: { email: 1 }, - }); - } - ); - }); - - describe('convertEmailToLowercase', () => { - const dummyStorageAdapter = { - createObject: () => Promise.resolve({ ops: [{}] }), - findOneAndUpdate: () => Promise.resolve({}), - watch: () => Promise.resolve(), - getAllClasses: () => - Promise.resolve([ - { - className: '_User', - fields: { email: 'String' }, - indexes: {}, - classLevelPermissions: { protectedFields: {} }, - }, - ]), - }; - const dates = { - createdAt: { iso: undefined, __type: 'Date' }, - updatedAt: { iso: undefined, __type: 'Date' }, - }; - - it('should not transform email to lower case without convertEmailToLowercase option on create', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, {}); - const spy = spyOn(dummyStorageAdapter, 'createObject'); - spy.and.callThrough(); - await databaseController.create('_User', { - email: 'EXAMPLE@EXAMPLE.COM', - }); - expect(spy.calls.all()[0].args[2]).toEqual({ - email: 'EXAMPLE@EXAMPLE.COM', - ...dates, - }); - }); - - it('should transform email to lower case with convertEmailToLowercase option on create', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, { - convertEmailToLowercase: true, - }); - const spy = spyOn(dummyStorageAdapter, 'createObject'); - spy.and.callThrough(); - await databaseController.create('_User', { - email: 'EXAMPLE@EXAMPLE.COM', - }); - expect(spy.calls.all()[0].args[2]).toEqual({ - email: 'example@example.com', - ...dates, - }); - }); - - it('should not transform email to lower case without convertEmailToLowercase option on update', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, {}); - const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); - spy.and.callThrough(); - await databaseController.update('_User', { id: 'example' }, { email: 'EXAMPLE@EXAMPLE.COM' }); - expect(spy.calls.all()[0].args[3]).toEqual({ - email: 'EXAMPLE@EXAMPLE.COM', - }); - }); - - it('should transform email to lower case with convertEmailToLowercase option on update', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, { - convertEmailToLowercase: true, - }); - const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); - spy.and.callThrough(); - await databaseController.update('_User', { id: 'example' }, { email: 'EXAMPLE@EXAMPLE.COM' }); - expect(spy.calls.all()[0].args[3]).toEqual({ - email: 'example@example.com', - }); - }); - - it('should not find a case insensitive user by email with convertEmailToLowercase', async () => { - await reconfigureServer({ convertEmailToLowercase: true }); - const user = new Parse.User(); - await user.save({ username: 'EXAMPLE', email: 'EXAMPLE@EXAMPLE.COM', password: 'password' }); - - const query = new Parse.Query(Parse.User); - query.equalTo('email', 'EXAMPLE@EXAMPLE.COM'); - const result = await query.find({ useMasterKey: true }); - expect(result.length).toEqual(0); - - const query2 = new Parse.Query(Parse.User); - query2.equalTo('email', 'example@example.com'); - const result2 = await query2.find({ useMasterKey: true }); - expect(result2.length).toEqual(1); - }); - }); - - describe('convertUsernameToLowercase', () => { - const dummyStorageAdapter = { - createObject: () => Promise.resolve({ ops: [{}] }), - findOneAndUpdate: () => Promise.resolve({}), - watch: () => Promise.resolve(), - getAllClasses: () => - Promise.resolve([ - { - className: '_User', - fields: { username: 'String' }, - indexes: {}, - classLevelPermissions: { protectedFields: {} }, - }, - ]), - }; - const dates = { - createdAt: { iso: undefined, __type: 'Date' }, - updatedAt: { iso: undefined, __type: 'Date' }, - }; - - it('should not transform username to lower case without convertUsernameToLowercase option on create', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, {}); - const spy = spyOn(dummyStorageAdapter, 'createObject'); - spy.and.callThrough(); - await databaseController.create('_User', { - username: 'EXAMPLE', - }); - expect(spy.calls.all()[0].args[2]).toEqual({ - username: 'EXAMPLE', - ...dates, - }); - }); - - it('should transform username to lower case with convertUsernameToLowercase option on create', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, { - convertUsernameToLowercase: true, - }); - const spy = spyOn(dummyStorageAdapter, 'createObject'); - spy.and.callThrough(); - await databaseController.create('_User', { - username: 'EXAMPLE', - }); - expect(spy.calls.all()[0].args[2]).toEqual({ - username: 'example', - ...dates, - }); - }); - - it('should not transform username to lower case without convertUsernameToLowercase option on update', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, {}); - const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); - spy.and.callThrough(); - await databaseController.update('_User', { id: 'example' }, { username: 'EXAMPLE' }); - expect(spy.calls.all()[0].args[3]).toEqual({ - username: 'EXAMPLE', - }); - }); - - it('should transform username to lower case with convertUsernameToLowercase option on update', async () => { - const databaseController = new DatabaseController(dummyStorageAdapter, { - convertUsernameToLowercase: true, - }); - const spy = spyOn(dummyStorageAdapter, 'findOneAndUpdate'); - spy.and.callThrough(); - await databaseController.update('_User', { id: 'example' }, { username: 'EXAMPLE' }); - expect(spy.calls.all()[0].args[3]).toEqual({ - username: 'example', - }); - }); - - it('should not find a case insensitive user by username with convertUsernameToLowercase', async () => { - await reconfigureServer({ convertUsernameToLowercase: true }); - const user = new Parse.User(); - await user.save({ username: 'EXAMPLE', password: 'password' }); - - const query = new Parse.Query(Parse.User); - query.equalTo('username', 'EXAMPLE'); - const result = await query.find({ useMasterKey: true }); - expect(result.length).toEqual(0); - - const query2 = new Parse.Query(Parse.User); - query2.equalTo('username', 'example'); - const result2 = await query2.find({ useMasterKey: true }); - expect(result2.length).toEqual(1); - }); - }); }); function buildCLP(pointerNames) { diff --git a/spec/DefinedSchemas.spec.js b/spec/DefinedSchemas.spec.js index a1c7e3dca5..8d8853766e 100644 --- a/spec/DefinedSchemas.spec.js +++ b/spec/DefinedSchemas.spec.js @@ -554,7 +554,7 @@ describe('DefinedSchemas', () => { }); }); - it('should not delete classes automatically', async () => { + it('should not delete automatically classes', async () => { await reconfigureServer({ schema: { definitions: [{ className: '_User' }, { className: 'Test' }] }, }); diff --git a/spec/EmailVerificationToken.spec.js b/spec/EmailVerificationToken.spec.js index 39ad6e5edd..e21a049719 100644 --- a/spec/EmailVerificationToken.spec.js +++ b/spec/EmailVerificationToken.spec.js @@ -3,7 +3,6 @@ const Auth = require('../lib/Auth'); const Config = require('../lib/Config'); const request = require('../lib/request'); -const MockEmailAdapterWithOptions = require('./support/MockEmailAdapterWithOptions'); describe('Email Verification Token Expiration: ', () => { it('show the invalid verification link page, if the user clicks on the verify email link after the email verify token expires', done => { @@ -127,7 +126,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { request({ url: sendEmailOptions.link, @@ -169,7 +167,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { request({ url: sendEmailOptions.link, @@ -217,7 +214,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { request({ url: sendEmailOptions.link, @@ -292,223 +288,6 @@ describe('Email Verification Token Expiration: ', () => { }); }); - it('can conditionally send emails', async () => { - let sendEmailOptions; - const emailAdapter = { - sendVerificationEmail: options => { - sendEmailOptions = options; - }, - sendPasswordResetEmail: () => Promise.resolve(), - sendMail: () => {}, - }; - const verifyUserEmails = { - method(req) { - expect(Object.keys(req)).toEqual(['original', 'object', 'master', 'ip', 'installationId']); - return false; - }, - }; - const verifySpy = spyOn(verifyUserEmails, 'method').and.callThrough(); - await reconfigureServer({ - appName: 'emailVerifyToken', - verifyUserEmails: verifyUserEmails.method, - emailAdapter: emailAdapter, - emailVerifyTokenValidityDuration: 5, // 5 seconds - publicServerURL: 'http://localhost:8378/1', - }); - const beforeSave = { - method(req) { - req.object.set('emailVerified', true); - }, - }; - const saveSpy = spyOn(beforeSave, 'method').and.callThrough(); - const emailSpy = spyOn(emailAdapter, 'sendVerificationEmail').and.callThrough(); - Parse.Cloud.beforeSave(Parse.User, beforeSave.method); - const user = new Parse.User(); - user.setUsername('sets_email_verify_token_expires_at'); - user.setPassword('expiringToken'); - user.set('email', 'user@example.com'); - await user.signUp(); - - const config = Config.get('test'); - const results = await config.database.find( - '_User', - { - username: 'sets_email_verify_token_expires_at', - }, - {}, - Auth.maintenance(config) - ); - - expect(results.length).toBe(1); - const user_data = results[0]; - expect(typeof user_data).toBe('object'); - expect(user_data.emailVerified).toEqual(true); - expect(user_data._email_verify_token).toBeUndefined(); - expect(user_data._email_verify_token_expires_at).toBeUndefined(); - expect(emailSpy).not.toHaveBeenCalled(); - expect(saveSpy).toHaveBeenCalled(); - expect(sendEmailOptions).toBeUndefined(); - expect(verifySpy).toHaveBeenCalled(); - }); - - it('can conditionally send emails and allow conditional login', async () => { - let sendEmailOptions; - const emailAdapter = { - sendVerificationEmail: options => { - sendEmailOptions = options; - }, - sendPasswordResetEmail: () => Promise.resolve(), - sendMail: () => {}, - }; - const verifyUserEmails = { - method(req) { - expect(Object.keys(req)).toEqual(['original', 'object', 'master', 'ip', 'installationId']); - if (req.object.get('username') === 'no_email') { - return false; - } - return true; - }, - }; - const verifySpy = spyOn(verifyUserEmails, 'method').and.callThrough(); - await reconfigureServer({ - appName: 'emailVerifyToken', - verifyUserEmails: verifyUserEmails.method, - preventLoginWithUnverifiedEmail: verifyUserEmails.method, - emailAdapter: emailAdapter, - emailVerifyTokenValidityDuration: 5, // 5 seconds - publicServerURL: 'http://localhost:8378/1', - }); - const user = new Parse.User(); - user.setUsername('no_email'); - user.setPassword('expiringToken'); - user.set('email', 'user@example.com'); - await user.signUp(); - expect(sendEmailOptions).toBeUndefined(); - expect(user.getSessionToken()).toBeDefined(); - expect(verifySpy).toHaveBeenCalledTimes(2); - const user2 = new Parse.User(); - user2.setUsername('email'); - user2.setPassword('expiringToken'); - user2.set('email', 'user2@example.com'); - await user2.signUp(); - await jasmine.timeout(); - expect(user2.getSessionToken()).toBeUndefined(); - expect(sendEmailOptions).toBeDefined(); - expect(verifySpy).toHaveBeenCalledTimes(5); - }); - - it('can conditionally send user email verification', async () => { - const emailAdapter = { - sendVerificationEmail: () => {}, - sendPasswordResetEmail: () => Promise.resolve(), - sendMail: () => {}, - }; - const sendVerificationEmail = { - method(req) { - expect(req.user).toBeDefined(); - expect(req.master).toBeDefined(); - return false; - }, - }; - const sendSpy = spyOn(sendVerificationEmail, 'method').and.callThrough(); - await reconfigureServer({ - appName: 'emailVerifyToken', - verifyUserEmails: true, - emailAdapter: emailAdapter, - emailVerifyTokenValidityDuration: 5, // 5 seconds - publicServerURL: 'http://localhost:8378/1', - sendUserEmailVerification: sendVerificationEmail.method, - }); - const emailSpy = spyOn(emailAdapter, 'sendVerificationEmail').and.callThrough(); - const newUser = new Parse.User(); - newUser.setUsername('unsets_email_verify_token_expires_at'); - newUser.setPassword('expiringToken'); - newUser.set('email', 'user@example.com'); - await newUser.signUp(); - await Parse.User.requestEmailVerification('user@example.com'); - await jasmine.timeout(); - expect(sendSpy).toHaveBeenCalledTimes(2); - expect(emailSpy).toHaveBeenCalledTimes(0); - }); - - it('provides full user object in email verification function on email and username change', async () => { - const emailAdapter = { - sendVerificationEmail: () => {}, - sendPasswordResetEmail: () => Promise.resolve(), - sendMail: () => {}, - }; - const sendVerificationEmail = { - method(req) { - expect(req.user).toBeDefined(); - expect(req.user.id).toBeDefined(); - expect(req.user.get('createdAt')).toBeDefined(); - expect(req.user.get('updatedAt')).toBeDefined(); - expect(req.master).toBeDefined(); - return false; - }, - }; - await reconfigureServer({ - appName: 'emailVerifyToken', - verifyUserEmails: true, - emailAdapter: emailAdapter, - emailVerifyTokenValidityDuration: 5, - publicServerURL: 'http://localhost:8378/1', - sendUserEmailVerification: sendVerificationEmail.method, - }); - const user = new Parse.User(); - user.setPassword('password'); - user.setUsername('new@example.com'); - user.setEmail('user@example.com'); - await user.save(null, { useMasterKey: true }); - - // Update email and username - user.setUsername('new@example.com'); - user.setEmail('new@example.com'); - await user.save(null, { useMasterKey: true }); - }); - - it('beforeSave options do not change existing behaviour', async () => { - let sendEmailOptions; - const emailAdapter = { - sendVerificationEmail: options => { - sendEmailOptions = options; - }, - sendPasswordResetEmail: () => Promise.resolve(), - sendMail: () => {}, - }; - await reconfigureServer({ - appName: 'emailVerifyToken', - verifyUserEmails: true, - emailAdapter: emailAdapter, - emailVerifyTokenValidityDuration: 5, // 5 seconds - publicServerURL: 'http://localhost:8378/1', - }); - const emailSpy = spyOn(emailAdapter, 'sendVerificationEmail').and.callThrough(); - const newUser = new Parse.User(); - newUser.setUsername('unsets_email_verify_token_expires_at'); - newUser.setPassword('expiringToken'); - newUser.set('email', 'user@parse.com'); - await newUser.signUp(); - await jasmine.timeout(); - const response = await request({ - url: sendEmailOptions.link, - followRedirects: false, - }); - expect(response.status).toEqual(302); - const config = Config.get('test'); - const results = await config.database.find('_User', { - username: 'unsets_email_verify_token_expires_at', - }); - - expect(results.length).toBe(1); - const user = results[0]; - expect(typeof user).toBe('object'); - expect(user.emailVerified).toEqual(true); - expect(typeof user._email_verify_token).toBe('undefined'); - expect(typeof user._email_verify_token_expires_at).toBe('undefined'); - expect(emailSpy).toHaveBeenCalled(); - }); - it('unsets the _email_verify_token_expires_at and _email_verify_token fields in the User class if email verification is successful', done => { const user = new Parse.User(); let sendEmailOptions; @@ -532,7 +311,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { request({ url: sendEmailOptions.link, @@ -592,7 +370,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { return request({ url: sendEmailOptions.link, @@ -810,9 +587,6 @@ describe('Email Verification Token Expiration: ', () => { }) .then(response => { expect(response.status).toBe(200); - }) - .then(() => jasmine.timeout()) - .then(() => { expect(sendVerificationEmailCallCount).toBe(2); expect(sendEmailOptions).toBeDefined(); @@ -842,41 +616,6 @@ describe('Email Verification Token Expiration: ', () => { }); }); - it('provides function arguments in verifyUserEmails on verificationEmailRequest', async () => { - const user = new Parse.User(); - user.setUsername('user'); - user.setPassword('pass'); - user.set('email', 'test@example.com'); - await user.signUp(); - - const verifyUserEmails = { - method: async (params) => { - expect(params.object).toBeInstanceOf(Parse.User); - expect(params.ip).toBeDefined(); - expect(params.master).toBeDefined(); - expect(params.installationId).toBeDefined(); - expect(params.resendRequest).toBeTrue(); - return true; - }, - }; - const verifyUserEmailsSpy = spyOn(verifyUserEmails, 'method').and.callThrough(); - await reconfigureServer({ - appName: 'test', - publicServerURL: 'http://localhost:1337/1', - verifyUserEmails: verifyUserEmails.method, - preventLoginWithUnverifiedEmail: verifyUserEmails.method, - preventSignupWithUnverifiedEmail: true, - emailAdapter: MockEmailAdapterWithOptions({ - fromAddress: 'parse@example.com', - apiKey: 'k', - domain: 'd', - }), - }); - - await expectAsync(Parse.User.requestEmailVerification('test@example.com')).toBeResolved(); - expect(verifyUserEmailsSpy).toHaveBeenCalledTimes(1); - }); - it('should throw with invalid emailVerifyTokenReuseIfValid', async done => { const sendEmailOptions = []; const emailAdapter = { @@ -944,7 +683,7 @@ describe('Email Verification Token Expiration: ', () => { const config = Config.get('test'); const [userBeforeRequest] = await config.database.find('_User', { username: 'resends_verification_token', - }, {}, Auth.maintenance(config)); + }); // store this user before we make our email request expect(sendVerificationEmailCallCount).toBe(1); await new Promise(resolve => { @@ -964,21 +703,20 @@ describe('Email Verification Token Expiration: ', () => { 'Content-Type': 'application/json', }, }); - await jasmine.timeout(); expect(response.status).toBe(200); expect(sendVerificationEmailCallCount).toBe(2); expect(sendEmailOptions).toBeDefined(); const [userAfterRequest] = await config.database.find('_User', { username: 'resends_verification_token', - }, {}, Auth.maintenance(config)); + }); - // Verify that token & expiration haven't been changed for this new request + // verify that our token & expiration has been changed for this new request expect(typeof userAfterRequest).toBe('object'); - expect(userBeforeRequest._email_verify_token).toBeDefined(); expect(userBeforeRequest._email_verify_token).toEqual(userAfterRequest._email_verify_token); - expect(userBeforeRequest._email_verify_token_expires_at).toBeDefined(); - expect(userBeforeRequest._email_verify_token_expires_at).toEqual(userAfterRequest._email_verify_token_expires_at); + expect(userBeforeRequest._email_verify_token_expires_at).toEqual( + userAfterRequest._email_verify_token_expires_at + ); done(); }); @@ -1007,7 +745,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { return request({ url: sendEmailOptions.link, @@ -1246,7 +983,6 @@ describe('Email Verification Token Expiration: ', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { request({ url: sendEmailOptions.link, diff --git a/spec/Middlewares.spec.js b/spec/Middlewares.spec.js index 7ec50bd434..636e7809f9 100644 --- a/spec/Middlewares.spec.js +++ b/spec/Middlewares.spec.js @@ -1,19 +1,10 @@ const middlewares = require('../lib/middlewares'); const AppCache = require('../lib/cache').AppCache; -const { BlockList } = require('net'); - -const AppCachePut = (appId, config) => - AppCache.put(appId, { - ...config, - maintenanceKeyIpsStore: new Map(), - masterKeyIpsStore: new Map(), - }); describe('middlewares', () => { let fakeReq, fakeRes; beforeEach(() => { fakeReq = { - ip: '127.0.0.1', originalUrl: 'http://example.com/parse/', url: 'http://example.com/', body: { @@ -25,7 +16,7 @@ describe('middlewares', () => { }, }; fakeRes = jasmine.createSpyObj('fakeRes', ['end', 'status']); - AppCachePut(fakeReq.body._ApplicationId, {}); + AppCache.put(fakeReq.body._ApplicationId, {}); }); afterEach(() => { @@ -44,7 +35,7 @@ describe('middlewares', () => { }); it('should give invalid response when keys are configured but no key supplied', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', restAPIKey: 'restAPIKey', }); @@ -53,7 +44,7 @@ describe('middlewares', () => { }); it('should give invalid response when keys are configured but supplied key is incorrect', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', restAPIKey: 'restAPIKey', }); @@ -63,7 +54,7 @@ describe('middlewares', () => { }); it('should give invalid response when keys are configured but different key is supplied', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', restAPIKey: 'restAPIKey', }); @@ -73,7 +64,7 @@ describe('middlewares', () => { }); it('should succeed when any one of the configured keys supplied', done => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { clientKey: 'clientKey', masterKey: 'masterKey', restAPIKey: 'restAPIKey', @@ -86,7 +77,7 @@ describe('middlewares', () => { }); it('should succeed when client key supplied but empty', done => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { clientKey: '', masterKey: 'masterKey', restAPIKey: 'restAPIKey', @@ -99,7 +90,7 @@ describe('middlewares', () => { }); it('should succeed when no keys are configured and none supplied', done => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', }); middlewares.handleParseHeaders(fakeReq, fakeRes, () => { @@ -126,7 +117,7 @@ describe('middlewares', () => { otherKey => otherKey !== infoKey && otherKey !== 'javascriptKey' ); it(`it should pull ${bodyKey} into req.info`, done => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKeyIps: ['0.0.0.0/0'], }); fakeReq.ip = '127.0.0.1'; @@ -147,7 +138,7 @@ describe('middlewares', () => { 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, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['10.0.0.1'], }); @@ -161,7 +152,7 @@ describe('middlewares', () => { }); it('should not succeed if the ip does not belong to masterKeyIps list', async () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['10.0.0.1'], }); @@ -174,7 +165,7 @@ describe('middlewares', () => { it('should not succeed 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, { + AppCache.put(fakeReq.body._ApplicationId, { maintenanceKey: 'masterKey', maintenanceKeyIps: ['10.0.0.0', '10.0.0.1'], }); @@ -188,7 +179,7 @@ describe('middlewares', () => { }); it('should succeed if the ip does belong to masterKeyIps list', async () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['10.0.0.1'], }); @@ -199,7 +190,7 @@ describe('middlewares', () => { }); it('should allow any ip to use masterKey if masterKeyIps is empty', async () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', masterKeyIps: ['0.0.0.0/0'], }); @@ -230,7 +221,7 @@ describe('middlewares', () => { }); it('should set default Access-Control-Allow-Headers if allowHeaders are empty', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { allowHeaders: undefined, }); const headers = {}; @@ -243,7 +234,7 @@ describe('middlewares', () => { allowCrossDomain(fakeReq, res, () => {}); expect(headers['Access-Control-Allow-Headers']).toContain(middlewares.DEFAULT_ALLOWED_HEADERS); - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { allowHeaders: [], }); allowCrossDomain(fakeReq, res, () => {}); @@ -251,7 +242,7 @@ describe('middlewares', () => { }); it('should append custom headers to Access-Control-Allow-Headers if allowHeaders provided', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { allowHeaders: ['Header-1', 'Header-2'], }); const headers = {}; @@ -267,7 +258,7 @@ describe('middlewares', () => { }); it('should set default Access-Control-Allow-Origin if allowOrigin is empty', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { allowOrigin: undefined, }); const headers = {}; @@ -282,7 +273,7 @@ describe('middlewares', () => { }); it('should set custom origin to Access-Control-Allow-Origin if allowOrigin is provided', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { allowOrigin: 'https://parseplatform.org/', }); const headers = {}; @@ -326,7 +317,7 @@ describe('middlewares', () => { }); it('should use user provided on field userFromJWT', done => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', }); fakeReq.userFromJWT = 'fake-user'; @@ -337,87 +328,11 @@ describe('middlewares', () => { }); it('should give invalid response when upload file without x-parse-application-id in header', () => { - AppCachePut(fakeReq.body._ApplicationId, { + AppCache.put(fakeReq.body._ApplicationId, { masterKey: 'masterKey', }); fakeReq.body = Buffer.from('fake-file'); middlewares.handleParseHeaders(fakeReq, fakeRes); expect(fakeRes.status).toHaveBeenCalledWith(403); }); - - it('should match address', () => { - const ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'; - const anotherIpv6 = '::ffff:101.10.0.1'; - const ipv4 = '192.168.0.101'; - const localhostV6 = '::1'; - const localhostV62 = '::ffff:127.0.0.1'; - const localhostV4 = '127.0.0.1'; - - const v6 = [ipv6, anotherIpv6]; - v6.forEach(ip => { - expect(middlewares.checkIp(ip, ['::/0'], new Map())).toBe(true); - expect(middlewares.checkIp(ip, ['::'], new Map())).toBe(true); - expect(middlewares.checkIp(ip, ['0.0.0.0'], new Map())).toBe(false); - expect(middlewares.checkIp(ip, ['0.0.0.0/0'], new Map())).toBe(false); - expect(middlewares.checkIp(ip, ['123.123.123.123'], new Map())).toBe(false); - }); - - expect(middlewares.checkIp(ipv6, [anotherIpv6], new Map())).toBe(false); - expect(middlewares.checkIp(ipv6, [ipv6], new Map())).toBe(true); - expect(middlewares.checkIp(ipv6, ['2001:db8:85a3:0:0:8a2e:0:0/100'], new Map())).toBe(true); - - expect(middlewares.checkIp(ipv4, ['::'], new Map())).toBe(false); - expect(middlewares.checkIp(ipv4, ['::/0'], new Map())).toBe(false); - expect(middlewares.checkIp(ipv4, ['0.0.0.0'], new Map())).toBe(true); - expect(middlewares.checkIp(ipv4, ['0.0.0.0/0'], new Map())).toBe(true); - expect(middlewares.checkIp(ipv4, ['123.123.123.123'], new Map())).toBe(false); - expect(middlewares.checkIp(ipv4, [ipv4], new Map())).toBe(true); - expect(middlewares.checkIp(ipv4, ['192.168.0.0/24'], new Map())).toBe(true); - - expect(middlewares.checkIp(localhostV4, ['::1'], new Map())).toBe(false); - expect(middlewares.checkIp(localhostV6, ['::1'], new Map())).toBe(true); - // ::ffff:127.0.0.1 is a padded ipv4 address but not ::1 - expect(middlewares.checkIp(localhostV62, ['::1'], new Map())).toBe(false); - // ::ffff:127.0.0.1 is a padded ipv4 address and is a match for 127.0.0.1 - expect(middlewares.checkIp(localhostV62, ['127.0.0.1'], new Map())).toBe(true); - }); - - it('should match address with cache', () => { - const ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'; - const cache1 = new Map(); - const spyBlockListCheck = spyOn(BlockList.prototype, 'check').and.callThrough(); - expect(middlewares.checkIp(ipv6, ['::'], cache1)).toBe(true); - expect(cache1.get('2001:0db8:85a3:0000:0000:8a2e:0370:7334')).toBe(undefined); - expect(cache1.get('allowAllIpv6')).toBe(true); - expect(spyBlockListCheck).toHaveBeenCalledTimes(0); - - const cache2 = new Map(); - expect(middlewares.checkIp('::1', ['::1'], cache2)).toBe(true); - expect(cache2.get('::1')).toBe(true); - expect(spyBlockListCheck).toHaveBeenCalledTimes(1); - expect(middlewares.checkIp('::1', ['::1'], cache2)).toBe(true); - expect(spyBlockListCheck).toHaveBeenCalledTimes(1); - spyBlockListCheck.calls.reset(); - - const cache3 = new Map(); - expect(middlewares.checkIp('127.0.0.1', ['127.0.0.1'], cache3)).toBe(true); - expect(cache3.get('127.0.0.1')).toBe(true); - expect(spyBlockListCheck).toHaveBeenCalledTimes(1); - expect(middlewares.checkIp('127.0.0.1', ['127.0.0.1'], cache3)).toBe(true); - expect(spyBlockListCheck).toHaveBeenCalledTimes(1); - spyBlockListCheck.calls.reset(); - - const cache4 = new Map(); - const ranges = ['127.0.0.1', '192.168.0.0/24']; - // should not cache negative match - expect(middlewares.checkIp('123.123.123.123', ranges, cache4)).toBe(false); - expect(cache4.get('123.123.123.123')).toBe(undefined); - expect(spyBlockListCheck).toHaveBeenCalledTimes(1); - spyBlockListCheck.calls.reset(); - - // should not cache cidr - expect(middlewares.checkIp('192.168.0.101', ranges, cache4)).toBe(true); - expect(cache4.get('192.168.0.101')).toBe(undefined); - expect(spyBlockListCheck).toHaveBeenCalledTimes(1); - }); }); diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index e7bbfe0cd8..1b5cc0c5e9 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -254,47 +254,6 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue(); }); - it('upserts with $setOnInsert', async () => { - const uuid = require('uuid'); - const uuid1 = uuid.v4(); - const uuid2 = uuid.v4(); - const schema = { - className: 'MyClass', - fields: { - x: { type: 'Number' }, - count: { type: 'Number' }, - }, - classLevelPermissions: {}, - }; - - const myClassSchema = new Parse.Schema(schema.className); - myClassSchema.setCLP(schema.classLevelPermissions); - await myClassSchema.save(); - - const query = { - x: 1, - }; - const update = { - objectId: { - __op: 'SetOnInsert', - amount: uuid1, - }, - count: { - __op: 'Increment', - amount: 1, - }, - }; - await Parse.Server.database.update('MyClass', query, update, { upsert: true }); - update.objectId.amount = uuid2; - await Parse.Server.database.update('MyClass', query, update, { upsert: true }); - - const res = await Parse.Server.database.find(schema.className, {}, {}); - expect(res.length).toBe(1); - expect(res[0].objectId).toBe(uuid1); - expect(res[0].count).toBe(2); - expect(res[0].x).toBe(1); - }); - it('handles updating a single object with array, object date', done => { const adapter = new MongoStorageAdapter({ uri: databaseURI }); diff --git a/spec/PagesRouter.spec.js b/spec/PagesRouter.spec.js index 5f86922b08..e50144f1fe 100644 --- a/spec/PagesRouter.spec.js +++ b/spec/PagesRouter.spec.js @@ -749,7 +749,6 @@ 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); @@ -778,7 +777,6 @@ 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); @@ -832,7 +830,6 @@ 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); @@ -849,8 +846,6 @@ describe('Pages Router', () => { const locale = linkResponse.headers['x-parse-page-param-locale']; const username = linkResponse.headers['x-parse-page-param-username']; const publicServerUrl = linkResponse.headers['x-parse-page-param-publicserverurl']; - await jasmine.timeout(); - const invalidVerificationPagePath = pageResponse.calls.all()[0].args[0]; expect(appId).toBeDefined(); expect(locale).toBe(exampleLocale); @@ -1195,7 +1190,6 @@ 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({ @@ -1203,6 +1197,7 @@ 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}`)); }); diff --git a/spec/Parse.Push.spec.js b/spec/Parse.Push.spec.js index 143922852d..1732e426e3 100644 --- a/spec/Parse.Push.spec.js +++ b/spec/Parse.Push.spec.js @@ -2,12 +2,14 @@ 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 jasmine.timeout(); + await sleep(100); result = await query.first({ useMasterKey: true }); } }; diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index 4f8190a4a6..9b1a97af87 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -1267,25 +1267,6 @@ describe('miscellaneous', function () { }); }); - it('test cloud function query parameters with array of pointers', async () => { - Parse.Cloud.define('echoParams', req => { - return req.params; - }); - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': 'test', - 'X-Parse-Javascript-Key': 'test', - }; - const response = await request({ - method: 'POST', - headers: headers, - url: 'http://localhost:8378/1/functions/echoParams', - body: '{"arr": [{ "__type": "Pointer", "className": "PointerTest" }]}', - }); - const res = response.data.result; - expect(res.arr.length).toEqual(1); - }); - it('can handle null params in cloud functions (regression test for #1742)', done => { Parse.Cloud.define('func', request => { expect(request.params.nullParam).toEqual(null); diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index e36929636b..eeab537008 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -1364,107 +1364,11 @@ describe('Parse.File testing', () => { ); }); - it('works with a period in the file name', async () => { - await reconfigureServer({ - fileUpload: { - enableForPublic: true, - fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], - }, - }); - const headers = { - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - }; - - const values = ['file.png.html', 'file.txt.png.html', 'file.png.txt.html']; - - for (const value of values) { - await expectAsync( - request({ - method: 'POST', - headers: headers, - url: `http://localhost:8378/1/files/${value}`, - body: '\n', - }).catch(e => { - throw new Error(e.data.error); - }) - ).toBeRejectedWith( - new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`) - ); - } - }); - - it('works to stop invalid filenames', async () => { - await reconfigureServer({ - fileUpload: { - enableForPublic: true, - fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], - }, - }); - const headers = { - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - }; - - const values = [ - '!invalid.png', - '.png', - '.html', - ' .html', - '.png.html', - '~invalid.png', - '-invalid.png', - ]; - - for (const value of values) { - await expectAsync( - request({ - method: 'POST', - headers: headers, - url: `http://localhost:8378/1/files/${value}`, - body: '\n', - }).catch(e => { - throw new Error(e.data.error); - }) - ).toBeRejectedWith( - new Parse.Error(Parse.Error.INVALID_FILE_NAME, `Filename contains invalid characters.`) - ); - } - }); - - it('allows file without extension', async () => { - await reconfigureServer({ - fileUpload: { - enableForPublic: true, - fileExtensions: ['^[^hH][^tT][^mM][^lL]?$'], - }, - }); - const headers = { - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - }; - - const values = ['filenamewithoutextension']; - - for (const value of values) { - await expectAsync( - request({ - method: 'POST', - headers: headers, - url: `http://localhost:8378/1/files/${value}`, - body: '\n', - }).catch(e => { - throw new Error(e.data.error); - }) - ).toBeResolved(); - } - }); - it('works with array', async () => { await reconfigureServer({ fileUpload: { enableForPublic: true, - fileExtensions: ['jpg', 'wav'], + fileExtensions: ['jpg'], }, }); await expectAsync( @@ -1483,30 +1387,6 @@ describe('Parse.File testing', () => { ).toBeRejectedWith( new Parse.Error(Parse.Error.FILE_SAVE_ERROR, `File upload of extension html is disabled.`) ); - await expectAsync( - request({ - method: 'POST', - url: 'http://localhost:8378/1/files/file', - body: JSON.stringify({ - _ApplicationId: 'test', - _JavaScriptKey: 'test', - _ContentType: 'image/jpg', - base64: 'PGh0bWw+PC9odG1sPgo=', - }), - }) - ).toBeResolved(); - await expectAsync( - request({ - method: 'POST', - url: 'http://localhost:8378/1/files/file', - body: JSON.stringify({ - _ApplicationId: 'test', - _JavaScriptKey: 'test', - _ContentType: 'audio/wav', - base64: 'UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA', - }), - }) - ).toBeResolved(); }); it('works with array without Content-Type', async () => { diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 7ed1714d3c..87718da13a 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5275,6 +5275,7 @@ describe('ParseGraphQLServer', () => { it('should only count', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); const where = { @@ -6832,7 +6833,7 @@ describe('ParseGraphQLServer', () => { describe('Files Mutations', () => { describe('Create', () => { - it('should return File object', async () => { + it_only_node_version('<17')('should return File object', async () => { const clientMutationId = uuidv4(); parseServer = await global.reconfigureServer({ @@ -9298,7 +9299,7 @@ describe('ParseGraphQLServer', () => { expect(result6[0].node.name).toEqual('imACountry3'); }); - it('should support files', async () => { + it_only_node_version('<17')('should support files', async () => { try { parseServer = await global.reconfigureServer({ publicServerURL: 'http://localhost:13377/parse', @@ -9546,115 +9547,7 @@ describe('ParseGraphQLServer', () => { } }); - it('should support file upload for on fly creation through pointer and relation', async () => { - parseServer = await global.reconfigureServer({ - publicServerURL: 'http://localhost:13377/parse', - }); - const schema = new Parse.Schema('SomeClass'); - schema.addFile('someFileField'); - schema.addPointer('somePointerField', 'SomeClass'); - schema.addRelation('someRelationField', 'SomeClass'); - await schema.save(); - - const body = new FormData(); - body.append( - 'operations', - JSON.stringify({ - query: ` - mutation UploadFiles( - $fields: CreateSomeClassFieldsInput - ) { - createSomeClass( - input: { fields: $fields } - ) { - someClass { - id - someFileField { - name - url - } - somePointerField { - id - someFileField { - name - url - } - } - someRelationField { - edges { - node { - id - someFileField { - name - url - } - } - } - } - } - } - } - `, - variables: { - fields: { - someFileField: { upload: null }, - somePointerField: { - createAndLink: { - someFileField: { upload: null }, - }, - }, - someRelationField: { - createAndAdd: [ - { - someFileField: { upload: null }, - }, - ], - }, - }, - }, - }) - ); - body.append( - 'map', - JSON.stringify({ - 1: ['variables.fields.someFileField.upload'], - 2: ['variables.fields.somePointerField.createAndLink.someFileField.upload'], - 3: ['variables.fields.someRelationField.createAndAdd.0.someFileField.upload'], - }) - ); - body.append('1', 'My File Content someFileField', { - filename: 'someFileField.txt', - contentType: 'text/plain', - }); - body.append('2', 'My File Content somePointerField', { - filename: 'somePointerField.txt', - contentType: 'text/plain', - }); - body.append('3', 'My File Content someRelationField', { - filename: 'someRelationField.txt', - contentType: 'text/plain', - }); - - const res = await fetch('http://localhost:13377/graphql', { - method: 'POST', - headers, - body, - }); - expect(res.status).toEqual(200); - const result = await res.json(); - console.log(result); - expect(result.data.createSomeClass.someClass.someFileField.name).toEqual( - jasmine.stringMatching(/_someFileField.txt$/) - ); - expect(result.data.createSomeClass.someClass.somePointerField.someFileField.name).toEqual( - jasmine.stringMatching(/_somePointerField.txt$/) - ); - expect( - result.data.createSomeClass.someClass.someRelationField.edges[0].node.someFileField.name - ).toEqual(jasmine.stringMatching(/_someRelationField.txt$/)); - }); - - it('should not upload if file is too large', async () => { + it_only_node_version('<17')('should not upload if file is too large', async () => { parseGraphQLServer.parseServer.config.maxUploadSize = '1kb'; const body = new FormData(); diff --git a/spec/ParseHooks.spec.js b/spec/ParseHooks.spec.js index 16a2e17be3..f4bcc2e440 100644 --- a/spec/ParseHooks.spec.js +++ b/spec/ParseHooks.spec.js @@ -190,7 +190,7 @@ describe('Hooks', () => { it('should fail trying to create two times the same function', done => { Parse.Hooks.createFunction('my_new_function', 'http://url.com') - .then(() => jasmine.timeout()) + .then(() => new Promise(resolve => setTimeout(resolve, 100))) .then( () => { return Parse.Hooks.createFunction('my_new_function', 'http://url.com'); diff --git a/spec/ParseLiveQueryServer.spec.js b/spec/ParseLiveQueryServer.spec.js index 04fb3fff58..50f29d0aab 100644 --- a/spec/ParseLiveQueryServer.spec.js +++ b/spec/ParseLiveQueryServer.spec.js @@ -356,7 +356,7 @@ describe('ParseLiveQueryServer', function () { // Make sure we add subscriptionInfo to the client const args = client.addSubscriptionInfo.calls.first().args; expect(args[0]).toBe(requestId); - expect(args[1].keys).toBe(query.keys); + expect(args[1].fields).toBe(query.fields); expect(args[1].sessionToken).toBe(request.sessionToken); // Make sure we send subscribe response to the client expect(client.pushSubscribe).toHaveBeenCalledWith(requestId); @@ -417,7 +417,7 @@ describe('ParseLiveQueryServer', function () { // Make sure we add subscriptionInfo to the client 2 args = clientAgain.addSubscriptionInfo.calls.mostRecent().args; expect(args[0]).toBe(requestIdAgain); - expect(args[1].keys).toBe(queryAgain.keys); + expect(args[1].fields).toBe(queryAgain.fields); }); it('can handle unsubscribe command without clientId', function () { @@ -1081,7 +1081,7 @@ describe('ParseLiveQueryServer', function () { done(); }); - it('can handle create command with keys', async done => { + it('can handle create command with fields', async done => { jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client'); const Client = require('../lib/LiveQuery/Client').Client; const parseLiveQueryServer = new ParseLiveQueryServer({}); @@ -1131,6 +1131,61 @@ describe('ParseLiveQueryServer', function () { done(); }); + it('can deprecate fields', async () => { + const Deprecator = require('../lib/Deprecator/Deprecator'); + const spy = spyOn(Deprecator, 'logRuntimeDeprecation').and.callFake(() => {}); + jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client'); + const Client = require('../lib/LiveQuery/Client').Client; + const parseLiveQueryServer = new ParseLiveQueryServer({}); + // Make mock request message + const message = generateMockMessage(); + + const clientId = 1; + const parseWebSocket = { + clientId, + send: jasmine.createSpy('send'), + }; + const client = new Client(clientId, parseWebSocket); + spyOn(client, 'pushCreate').and.callThrough(); + parseLiveQueryServer.clients.set(clientId, client); + + // Add mock subscription + const requestId = 2; + const query = { + className: testClassName, + where: { + key: 'value', + }, + fields: ['test'], + }; + await addMockSubscription(parseLiveQueryServer, clientId, requestId, parseWebSocket, query); + // Mock _matchesSubscription to return matching + parseLiveQueryServer._matchesSubscription = function (parseObject) { + if (!parseObject) { + return false; + } + return true; + }; + parseLiveQueryServer._matchesACL = function () { + return Promise.resolve(true); + }; + + parseLiveQueryServer._onAfterSave(message); + + // Make sure we send create command to client + await timeout(); + + expect(client.pushCreate).toHaveBeenCalled(); + const args = parseWebSocket.send.calls.mostRecent().args; + const toSend = JSON.parse(args[0]); + expect(toSend.object).toBeDefined(); + expect(toSend.original).toBeUndefined(); + expect(spy).toHaveBeenCalledWith({ + usage: 'Subscribing using fields parameter', + solution: `Subscribe using "keys" instead.`, + }); + }); + it('can handle create command with watch', async () => { jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client'); const Client = require('../lib/LiveQuery/Client').Client; diff --git a/spec/ParseQuery.hint.spec.js b/spec/ParseQuery.hint.spec.js index 7ebffa4d34..c398aa0989 100644 --- a/spec/ParseQuery.hint.spec.js +++ b/spec/ParseQuery.hint.spec.js @@ -86,7 +86,6 @@ describe_only_db('mongo')('Parse.Query hint', () => { let result = await collection.aggregate([{ $group: { _id: '$foo' } }], { explain: true, }); - let { queryPlanner } = result[0].stages[0].$cursor; expect(queryPlanner.winningPlan.stage).toBe('COLLSCAN'); @@ -94,7 +93,6 @@ describe_only_db('mongo')('Parse.Query hint', () => { hint: '_id_', explain: true, }); - queryPlanner = result[0].stages[0].$cursor.queryPlanner; expect(queryPlanner.winningPlan.stage).toBe('FETCH'); expect(queryPlanner.winningPlan.inputStage.indexName).toBe('_id_'); diff --git a/spec/ParseRole.spec.js b/spec/ParseRole.spec.js index 31de5b661e..47fed865fb 100644 --- a/spec/ParseRole.spec.js +++ b/spec/ParseRole.spec.js @@ -142,7 +142,7 @@ describe('Parse Role testing', () => { return Promise.all(promises); }; - const restExecute = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough(); + const restExecute = spyOn(RestQuery.prototype, 'execute').and.callThrough(); let user, auth, getAllRolesSpy; createTestUser() diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index 4fa7cd2804..4d3beaf349 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -15,18 +15,51 @@ const cryptoUtils = require('../lib/cryptoUtils'); describe('allowExpiredAuthDataToken option', () => { it('should accept true value', async () => { + const logger = require('../lib/logger').logger; + const logSpy = spyOn(logger, 'warn').and.callFake(() => {}); await reconfigureServer({ allowExpiredAuthDataToken: true }); expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(true); + expect( + logSpy.calls + .all() + .filter( + log => + log.args[0] === + `DeprecationWarning: The Parse Server option 'allowExpiredAuthDataToken' default will change to 'false' in a future version.` + ).length + ).toEqual(0); }); it('should accept false value', async () => { + const logger = require('../lib/logger').logger; + const logSpy = spyOn(logger, 'warn').and.callFake(() => {}); await reconfigureServer({ allowExpiredAuthDataToken: false }); expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(false); - }); - - it('should default false', async () => { + expect( + logSpy.calls + .all() + .filter( + log => + log.args[0] === + `DeprecationWarning: The Parse Server option 'allowExpiredAuthDataToken' default will change to 'false' in a future version.` + ).length + ).toEqual(0); + }); + + it('should default true', async () => { + const logger = require('../lib/logger').logger; + const logSpy = spyOn(logger, 'warn').and.callFake(() => {}); await reconfigureServer({}); - expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(false); + expect(Config.get(Parse.applicationId).allowExpiredAuthDataToken).toBe(true); + expect( + logSpy.calls + .all() + .filter( + log => + log.args[0] === + `DeprecationWarning: The Parse Server option 'allowExpiredAuthDataToken' default will change to 'false' in a future version.` + ).length + ).toEqual(1); }); it('should enforce boolean values', async () => { @@ -74,36 +107,6 @@ describe('Parse.User testing', () => { } }); - it('user login with context', async () => { - let hit = 0; - const context = { foo: 'bar' }; - Parse.Cloud.beforeLogin(req => { - expect(req.context).toEqual(context); - hit++; - }); - Parse.Cloud.afterLogin(req => { - expect(req.context).toEqual(context); - hit++; - }); - await Parse.User.signUp('asdf', 'zxcv'); - await request({ - method: 'POST', - url: 'http://localhost:8378/1/login', - headers: { - 'X-Parse-Application-Id': Parse.applicationId, - 'X-Parse-REST-API-Key': 'rest', - 'X-Parse-Cloud-Context': JSON.stringify(context), - 'Content-Type': 'application/json', - }, - body: { - _method: 'GET', - username: 'asdf', - password: 'zxcv', - }, - }); - expect(hit).toBe(2); - }); - it('user login with non-string username with REST API', async done => { await Parse.User.signUp('asdf', 'zxcv'); request({ @@ -1845,7 +1848,7 @@ describe('Parse.User testing', () => { }); }); - it('should not allow login with expired authData token since allowExpiredAuthDataToken is set to false by default', async () => { + it('should allow login with expired authData token by default', async () => { const provider = { authData: { id: '12345', @@ -1871,7 +1874,37 @@ describe('Parse.User testing', () => { // In this case, we want success as it was valid once. // If the client needs an updated token, do lock the user out defaultConfiguration.auth.shortLivedAuth.setValidAccessToken('otherToken'); - await expectAsync(Parse.User._logInWith('shortLivedAuth', {})).toBeRejected(); + await Parse.User._logInWith('shortLivedAuth', {}); + }); + + it('should not allow login with expired authData token when allowExpiredAuthDataToken is set to false', async () => { + await reconfigureServer({ allowExpiredAuthDataToken: false }); + const provider = { + authData: { + id: '12345', + access_token: 'token', + }, + restoreAuthentication() { + return true; + }, + deauthenticate() { + provider.authData = {}; + }, + authenticate(options) { + options.success(this, provider.authData); + }, + getAuthType() { + return 'shortLivedAuth'; + }, + }; + defaultConfiguration.auth.shortLivedAuth.setValidAccessToken('token'); + Parse.User._registerAuthenticationProvider(provider); + await Parse.User._logInWith('shortLivedAuth', {}); + // Simulate a remotely expired token (like a short lived one) + // In this case, we want success as it was valid once. + // If the client needs an updated token, do lock the user out + defaultConfiguration.auth.shortLivedAuth.setValidAccessToken('otherToken'); + expectAsync(Parse.User._logInWith('shortLivedAuth', {})).toBeRejected(); }); it('should allow PUT request with stale auth Data', done => { @@ -3004,7 +3037,6 @@ describe('Parse.User testing', () => { }, }); }) - .then(() => jasmine.timeout()) .then(() => { expect(emailCalled).toBe(true); expect(emailOptions).not.toBeUndefined(); @@ -3162,35 +3194,6 @@ describe('Parse.User testing', () => { .catch(done.fail); }); - it('should return current session with expired expiration date', async () => { - await Parse.User.signUp('buser', 'somepass', null); - const response = await request({ - method: 'GET', - url: 'http://localhost:8378/1/classes/_Session', - headers: { - 'X-Parse-Application-Id': 'test', - 'X-Parse-Master-Key': 'test', - }, - }); - const body = response.data; - const id = body.results[0].objectId; - const expiresAt = new Date(new Date().setYear(2015)); - await request({ - method: 'PUT', - url: 'http://localhost:8378/1/classes/_Session/' + id, - headers: { - 'X-Parse-Application-Id': 'test', - 'X-Parse-Master-Key': 'test', - 'Content-Type': 'application/json', - }, - body: { - expiresAt: { __type: 'Date', iso: expiresAt.toISOString() }, - }, - }); - const session = await Parse.Session.current(); - expect(session.get('expiresAt')).toEqual(expiresAt); - }); - it('should not create extraneous session tokens', done => { const config = Config.get(Parse.applicationId); config.database diff --git a/spec/PushController.spec.js b/spec/PushController.spec.js index 572fc9bcf9..49613214f5 100644 --- a/spec/PushController.spec.js +++ b/spec/PushController.spec.js @@ -26,12 +26,14 @@ const successfulIOS = function (body, installations) { return Promise.all(promises); }; +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + const pushCompleted = async pushId => { const query = new Parse.Query('_PushStatus'); query.equalTo('objectId', pushId); let result = await query.first({ useMasterKey: true }); while (!(result && result.get('status') === 'succeeded')) { - await jasmine.timeout(); + await sleep(100); result = await query.first({ useMasterKey: true }); } }; @@ -560,7 +562,7 @@ describe('PushController', () => { }); const pushStatusId = await sendPush(payload, {}, config, auth); // it is enqueued so it can take time - await jasmine.timeout(1000); + await sleep(1000); Parse.serverURL = 'http://localhost:8378/1'; // GOOD url const result = await Parse.Push.getPushStatus(pushStatusId); expect(result).toBeDefined(); @@ -799,7 +801,7 @@ describe('PushController', () => { }); await Parse.Object.saveAll(installations); await pushController.sendPush(payload, {}, config, auth); - await jasmine.timeout(1000); + await sleep(1000); const query = new Parse.Query('_PushStatus'); const results = await query.find({ useMasterKey: true }); expect(results.length).toBe(1); @@ -854,7 +856,7 @@ describe('PushController', () => { const config = Config.get(Parse.applicationId); await Parse.Object.saveAll(installations); await pushController.sendPush(payload, {}, config, auth); - await jasmine.timeout(1000); + await sleep(1000); const query = new Parse.Query('_PushStatus'); const results = await query.find({ useMasterKey: true }); expect(results.length).toBe(1); diff --git a/spec/RestQuery.spec.js b/spec/RestQuery.spec.js index 023d3b4790..24e22ac4f5 100644 --- a/spec/RestQuery.spec.js +++ b/spec/RestQuery.spec.js @@ -399,16 +399,15 @@ describe('RestQuery.each', () => { } const config = Config.get('test'); await Parse.Object.saveAll(objects); - const query = await RestQuery({ - method: RestQuery.Method.find, + const query = new RestQuery( config, - auth: auth.master(config), - className: 'Object', - restWhere: { value: { $gt: 2 } }, - restOptions: { limit: 2 }, - }); + auth.master(config), + 'Object', + { value: { $gt: 2 } }, + { limit: 2 } + ); const spy = spyOn(query, 'execute').and.callThrough(); - const classSpy = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough(); + const classSpy = spyOn(RestQuery.prototype, 'execute').and.callThrough(); const results = []; await query.each(result => { expect(result.value).toBeGreaterThan(2); @@ -439,37 +438,34 @@ describe('RestQuery.each', () => { * Two queries needed since objectId are sorted and we can't know which one * going to be the first and then skip by the $gt added by each */ - const queryOne = await RestQuery({ - method: RestQuery.Method.get, + const queryOne = new RestQuery( config, - auth: auth.master(config), - className: 'Letter', - restWhere: { + auth.master(config), + 'Letter', + { numbers: { __type: 'Pointer', className: 'Number', objectId: object1.id, }, }, - restOptions: { limit: 1 }, - }); - - const queryTwo = await RestQuery({ - method: RestQuery.Method.get, + { limit: 1 } + ); + const queryTwo = new RestQuery( config, - auth: auth.master(config), - className: 'Letter', - restWhere: { + auth.master(config), + 'Letter', + { numbers: { __type: 'Pointer', className: 'Number', objectId: object2.id, }, }, - restOptions: { limit: 1 }, - }); + { limit: 1 } + ); - const classSpy = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough(); + const classSpy = spyOn(RestQuery.prototype, 'execute').and.callThrough(); const resultsOne = []; const resultsTwo = []; await queryOne.each(result => { diff --git a/spec/UserController.spec.js b/spec/UserController.spec.js index 03c979abe6..6bcc454baf 100644 --- a/spec/UserController.spec.js +++ b/spec/UserController.spec.js @@ -1,76 +1,55 @@ +const UserController = require('../lib/Controllers/UserController').UserController; const emailAdapter = require('./support/MockEmailAdapter'); -const Config = require('../lib/Config'); -const Auth = require('../lib/Auth'); describe('UserController', () => { + const user = { + _email_verify_token: 'testToken', + username: 'testUser', + email: 'test@example.com', + }; + describe('sendVerificationEmail', () => { describe('parseFrameURL not provided', () => { - it('uses publicServerURL', async () => { + it('uses publicServerURL', async done => { await reconfigureServer({ publicServerURL: 'http://www.example.com', customPages: { parseFrameURL: undefined, }, - verifyUserEmails: true, - emailAdapter, - appName: 'test', }); - - let emailOptions; emailAdapter.sendVerificationEmail = options => { - emailOptions = options; - return Promise.resolve(); + expect(options.link).toEqual( + 'http://www.example.com/apps/test/verify_email?token=testToken&username=testUser' + ); + emailAdapter.sendVerificationEmail = () => Promise.resolve(); + done(); }; - - const username = 'verificationUser'; - const user = new Parse.User(); - user.setUsername(username); - user.setPassword('pass'); - user.setEmail('verification@example.com'); - await user.signUp(); - - const config = Config.get('test'); - const rawUser = await config.database.find('_User', { username }, {}, Auth.maintenance(config)); - const rawUsername = rawUser[0].username; - const rawToken = rawUser[0]._email_verify_token; - expect(rawToken).toBeDefined(); - expect(rawUsername).toBe(username); - expect(emailOptions.link).toEqual(`http://www.example.com/apps/test/verify_email?token=${rawToken}&username=${username}`); + const userController = new UserController(emailAdapter, 'test', { + verifyUserEmails: true, + }); + userController.sendVerificationEmail(user); }); }); describe('parseFrameURL provided', () => { - it('uses parseFrameURL and includes the destination in the link parameter', async () => { + it('uses parseFrameURL and includes the destination in the link parameter', async done => { await reconfigureServer({ publicServerURL: 'http://www.example.com', customPages: { parseFrameURL: 'http://someother.example.com/handle-parse-iframe', }, - verifyUserEmails: true, - emailAdapter, - appName: 'test', }); - - let emailOptions; emailAdapter.sendVerificationEmail = options => { - emailOptions = options; - return Promise.resolve(); + expect(options.link).toEqual( + 'http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=testToken&username=testUser' + ); + emailAdapter.sendVerificationEmail = () => Promise.resolve(); + done(); }; - - const username = 'verificationUser'; - const user = new Parse.User(); - user.setUsername(username); - user.setPassword('pass'); - user.setEmail('verification@example.com'); - await user.signUp(); - - const config = Config.get('test'); - const rawUser = await config.database.find('_User', { username }, {}, Auth.maintenance(config)); - const rawUsername = rawUser[0].username; - const rawToken = rawUser[0]._email_verify_token; - expect(rawToken).toBeDefined(); - expect(rawUsername).toBe(username); - expect(emailOptions.link).toEqual(`http://someother.example.com/handle-parse-iframe?link=%2Fapps%2Ftest%2Fverify_email&token=${rawToken}&username=${username}`); + const userController = new UserController(emailAdapter, 'test', { + verifyUserEmails: true, + }); + userController.sendVerificationEmail(user); }); }); }); diff --git a/spec/ValidationAndPasswordsReset.spec.js b/spec/ValidationAndPasswordsReset.spec.js index fb163ad567..ab944e14c1 100644 --- a/spec/ValidationAndPasswordsReset.spec.js +++ b/spec/ValidationAndPasswordsReset.spec.js @@ -51,7 +51,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { user.setUsername('zxcv'); user.setEmail('testIfEnabled@parse.com'); await user.signUp(); - await jasmine.timeout(); expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled(); user.fetch().then(() => { expect(user.get('emailVerified')).toEqual(false); @@ -138,7 +137,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { spyOn(emailAdapter, 'sendVerificationEmail').and.callFake(options => { expect(options.link).not.toBeNull(); expect(options.link).not.toMatch(/token=undefined/); - expect(options.link).not.toMatch(/username=undefined/); Promise.resolve(); }); const user = new Parse.User(); @@ -185,7 +183,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { user.setUsername('zxcv'); user.set('email', 'testSendSimpleAdapter@parse.com'); await user.signUp(); - await jasmine.timeout(); expect(calls).toBe(1); user .fetch() @@ -245,66 +242,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { }); }); - it('prevents user from signup and login if email is not verified and preventLoginWithUnverifiedEmail is set to function returning true', async () => { - await reconfigureServer({ - appName: 'test', - publicServerURL: 'http://localhost:1337/1', - verifyUserEmails: async () => true, - preventLoginWithUnverifiedEmail: async () => true, - preventSignupWithUnverifiedEmail: true, - emailAdapter: MockEmailAdapterWithOptions({ - fromAddress: 'parse@example.com', - apiKey: 'k', - domain: 'd', - }), - }); - - const user = new Parse.User(); - user.setPassword('asdf'); - user.setUsername('zxcv'); - user.set('email', 'testInvalidConfig@parse.com'); - const signupRes = await user.signUp(null).catch(e => e); - expect(signupRes.message).toEqual('User email is not verified.'); - - const loginRes = await Parse.User.logIn('zxcv', 'asdf').catch(e => e); - expect(loginRes.message).toEqual('User email is not verified.'); - }); - - it('provides function arguments in verifyUserEmails on login', async () => { - const user = new Parse.User(); - user.setUsername('user'); - user.setPassword('pass'); - user.set('email', 'test@example.com'); - await user.signUp(); - - const verifyUserEmails = { - method: async (params) => { - expect(params.object).toBeInstanceOf(Parse.User); - expect(params.ip).toBeDefined(); - expect(params.master).toBeDefined(); - expect(params.installationId).toBeDefined(); - return true; - }, - }; - const verifyUserEmailsSpy = spyOn(verifyUserEmails, 'method').and.callThrough(); - await reconfigureServer({ - appName: 'test', - publicServerURL: 'http://localhost:1337/1', - verifyUserEmails: verifyUserEmails.method, - preventLoginWithUnverifiedEmail: verifyUserEmails.method, - preventSignupWithUnverifiedEmail: true, - emailAdapter: MockEmailAdapterWithOptions({ - fromAddress: 'parse@example.com', - apiKey: 'k', - domain: 'd', - }), - }); - - const res = await Parse.User.logIn('user', 'pass').catch(e => e); - expect(res.code).toBe(205); - expect(verifyUserEmailsSpy).toHaveBeenCalledTimes(2); - }); - it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', async () => { let sendEmailOptions; const emailAdapter = { @@ -326,7 +263,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { user.setUsername('user'); user.set('email', 'user@example.com'); await user.signUp(); - await jasmine.timeout(); expect(sendEmailOptions).not.toBeUndefined(); const response = await request({ url: sendEmailOptions.link, @@ -638,7 +574,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { user.setUsername('zxcv'); user.set('email', 'user@parse.com'); await user.signUp(); - await jasmine.timeout(); expect(emailSent).toBe(true); done(); }); @@ -666,7 +601,6 @@ describe('Custom Pages, Email Verification, Password Reset', () => { user.set('email', 'user@parse.com'); return user.signUp(); }) - .then(() => jasmine.timeout()) .then(() => { expect(sendEmailOptions).not.toBeUndefined(); request({ diff --git a/spec/VerifyUserPassword.spec.js b/spec/VerifyUserPassword.spec.js index 3d15a25e15..eef2485815 100644 --- a/spec/VerifyUserPassword.spec.js +++ b/spec/VerifyUserPassword.spec.js @@ -585,83 +585,4 @@ describe('Verify User Password', () => { done(); }); }); - - it('verify password of user with unverified email with master key and ignoreEmailVerification=true', async () => { - await reconfigureServer({ - publicServerURL: 'http://localhost:8378/', - appName: 'emailVerify', - verifyUserEmails: true, - preventLoginWithUnverifiedEmail: true, - emailAdapter: MockEmailAdapterWithOptions({ - fromAddress: 'parse@example.com', - apiKey: 'k', - domain: 'd', - }), - }); - - const user = new Parse.User(); - user.setUsername('user'); - user.setPassword('pass'); - user.setEmail('test@example.com'); - await user.signUp(); - - const { data: res } = await request({ - method: 'POST', - url: Parse.serverURL + '/verifyPassword', - headers: { - 'X-Parse-Master-Key': Parse.masterKey, - 'X-Parse-Application-Id': Parse.applicationId, - 'X-Parse-REST-API-Key': 'rest', - 'Content-Type': 'application/json', - }, - body: { - username: 'user', - password: 'pass', - ignoreEmailVerification: true, - }, - json: true, - }); - expect(res.objectId).toBe(user.id); - expect(Object.prototype.hasOwnProperty.call(res, 'sessionToken')).toEqual(false); - expect(Object.prototype.hasOwnProperty.call(res, 'password')).toEqual(false); - }); - - it('fails to verify password of user with unverified email with master key and ignoreEmailVerification=false', async () => { - await reconfigureServer({ - publicServerURL: 'http://localhost:8378/', - appName: 'emailVerify', - verifyUserEmails: true, - preventLoginWithUnverifiedEmail: true, - emailAdapter: MockEmailAdapterWithOptions({ - fromAddress: 'parse@example.com', - apiKey: 'k', - domain: 'd', - }), - }); - - const user = new Parse.User(); - user.setUsername('user'); - user.setPassword('pass'); - user.setEmail('test@example.com'); - await user.signUp(); - - const res = await request({ - method: 'POST', - url: Parse.serverURL + '/verifyPassword', - headers: { - 'X-Parse-Master-Key': Parse.masterKey, - 'X-Parse-Application-Id': Parse.applicationId, - 'X-Parse-REST-API-Key': 'rest', - 'Content-Type': 'application/json', - }, - body: { - username: 'user', - password: 'pass', - ignoreEmailVerification: false, - }, - json: true, - }).catch(e => e); - expect(res.status).toBe(400); - expect(res.text).toMatch(/User email is not verified/); - }); }); diff --git a/spec/configs/CLIConfigAuth.json b/spec/configs/CLIConfigAuth.json deleted file mode 100644 index 37a2a5f373..0000000000 --- a/spec/configs/CLIConfigAuth.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "appName": "test", - "appId": "test", - "masterKey": "test", - "logLevel": "error", - "auth": { - "facebook": { - "appIds": "test" - } - } -} diff --git a/spec/helper.js b/spec/helper.js index f17f105e85..445de26509 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -103,7 +103,6 @@ const defaultConfiguration = { restAPIKey: 'rest', webhookKey: 'hook', masterKey: 'test', - maintenanceKey: 'testing', readOnlyMasterKey: 'read-only-test', fileKey: 'test', directAccess: true, @@ -428,29 +427,6 @@ global.it_exclude_dbs = excluded => { } }; -let testExclusionList = []; -try { - // Fetch test exclusion list - testExclusionList = require('./testExclusionList.json'); - console.log(`Using test exclusion list with ${testExclusionList.length} entries`); -} catch(error) { - if(error.code !== 'MODULE_NOT_FOUND') { - throw error; - } -} - -// Disable test if its UUID is found in testExclusionList -global.it_id = (id, func) => { - if (testExclusionList.includes(id)) { - return xit; - } else { - if(func === undefined) - return it; - else - return func; - } -}; - global.it_only_db = db => { if ( process.env.PARSE_SERVER_TEST_DB === db || @@ -570,16 +546,6 @@ global.describe_only_db = db => { } }; -global.fdescribe_only_db = db => { - if (process.env.PARSE_SERVER_TEST_DB == db) { - return fdescribe; - } else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') { - return fdescribe; - } else { - return xdescribe; - } -}; - global.describe_only = validator => { if (validator()) { return describe; @@ -605,4 +571,4 @@ jasmine.restoreLibrary = function (library, name) { require(library)[name] = libraryCache[library][name]; }; -jasmine.timeout = (t = 100) => new Promise(resolve => setTimeout(resolve, t)); +jasmine.timeout = t => new Promise(resolve => setTimeout(resolve, t)); diff --git a/spec/rest.spec.js b/spec/rest.spec.js index dc4e78ad0a..02d2f5960b 100644 --- a/spec/rest.spec.js +++ b/spec/rest.spec.js @@ -136,117 +136,6 @@ describe('rest create', () => { }); }); - describe('with maintenance key', () => { - let req; - - async function getObject(id) { - const res = await request({ - headers: { - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - }, - method: 'GET', - url: `http://localhost:8378/1/classes/TestObject/${id}`, - }); - - return res.data; - } - - beforeEach(() => { - req = { - headers: { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': 'test', - 'X-Parse-REST-API-Key': 'rest', - 'X-Parse-Maintenance-Key': 'testing', - }, - method: 'POST', - url: 'http://localhost:8378/1/classes/TestObject', - }; - }); - - it('allows createdAt', async () => { - const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; - req.body = { createdAt }; - - const res = await request(req); - expect(res.data.createdAt).toEqual(createdAt.iso); - }); - - it('allows createdAt and updatedAt', async () => { - const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; - const updatedAt = { __type: 'Date', iso: '2019-02-01T00:00:00.000Z' }; - req.body = { createdAt, updatedAt }; - - const res = await request(req); - - const obj = await getObject(res.data.objectId); - expect(obj.createdAt).toEqual(createdAt.iso); - expect(obj.updatedAt).toEqual(updatedAt.iso); - }); - - it('allows createdAt, updatedAt, and additional field', async () => { - const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; - const updatedAt = { __type: 'Date', iso: '2019-02-01T00:00:00.000Z' }; - req.body = { createdAt, updatedAt, testing: 123 }; - - const res = await request(req); - - const obj = await getObject(res.data.objectId); - expect(obj.createdAt).toEqual(createdAt.iso); - expect(obj.updatedAt).toEqual(updatedAt.iso); - expect(obj.testing).toEqual(123); - }); - - it('cannot set updatedAt dated before createdAt', async () => { - const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; - const updatedAt = { __type: 'Date', iso: '2018-12-01T00:00:00.000Z' }; - req.body = { createdAt, updatedAt }; - - try { - await request(req); - fail(); - } catch (err) { - expect(err.data.code).toEqual(Parse.Error.VALIDATION_ERROR); - } - }); - - it('cannot set updatedAt without createdAt', async () => { - const updatedAt = { __type: 'Date', iso: '2018-12-01T00:00:00.000Z' }; - req.body = { updatedAt }; - - const res = await request(req); - - const obj = await getObject(res.data.objectId); - expect(obj.updatedAt).not.toEqual(updatedAt.iso); - }); - - it('handles bad types for createdAt and updatedAt', async () => { - const createdAt = 12345; - const updatedAt = true; - req.body = { createdAt, updatedAt }; - - try { - await request(req); - fail(); - } catch (err) { - expect(err.data.code).toEqual(Parse.Error.INCORRECT_TYPE); - } - }); - - it('cannot set createdAt or updatedAt without maintenance key', async () => { - const createdAt = { __type: 'Date', iso: '2019-01-01T00:00:00.000Z' }; - const updatedAt = { __type: 'Date', iso: '2019-02-01T00:00:00.000Z' }; - req.body = { createdAt, updatedAt }; - delete req.headers['X-Parse-Maintenance-Key']; - - const res = await request(req); - - expect(res.data.createdAt).not.toEqual(createdAt.iso); - expect(res.data.updatedAt).not.toEqual(updatedAt.iso); - }); - }); - it('handles array, object, date', done => { const now = new Date(); const obj = { @@ -771,38 +660,6 @@ describe('rest create', () => { }); }); - it('cannot get object in volatileClasses if not masterKey through pointer', async () => { - const masterKeyOnlyClassObject = new Parse.Object('_PushStatus'); - await masterKeyOnlyClassObject.save(null, { useMasterKey: true }); - const obj2 = new Parse.Object('TestObject'); - // Anyone is can basically create a pointer to any object - // or some developers can use master key in some hook to link - // private objects to standard objects - obj2.set('pointer', masterKeyOnlyClassObject); - await obj2.save(); - const query = new Parse.Query('TestObject'); - query.include('pointer'); - await expectAsync(query.get(obj2.id)).toBeRejectedWithError( - "Clients aren't allowed to perform the get operation on the _PushStatus collection." - ); - }); - - it('cannot get object in _GlobalConfig if not masterKey through pointer', async () => { - await Parse.Config.save({ privateData: 'secret' }, { privateData: true }); - const obj2 = new Parse.Object('TestObject'); - obj2.set('globalConfigPointer', { - __type: 'Pointer', - className: '_GlobalConfig', - objectId: 1, - }); - await obj2.save(); - const query = new Parse.Query('TestObject'); - query.include('globalConfigPointer'); - await expectAsync(query.get(obj2.id)).toBeRejectedWithError( - "Clients aren't allowed to perform the get operation on the _GlobalConfig collection." - ); - }); - it('locks down session', done => { let currentUser; Parse.User.signUp('foo', 'bar') diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 9bfafcffcb..5c83493c94 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -138,71 +138,6 @@ describe('Vulnerabilities', () => { ); }); - it('denies creating global config with polluted data', async () => { - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': 'test', - 'X-Parse-Master-Key': 'test', - }; - const params = { - method: 'PUT', - url: 'http://localhost:8378/1/config', - json: true, - body: { - params: { - welcomeMesssage: 'Welcome to Parse', - foo: { _bsontype: 'Code', code: 'shell' }, - }, - }, - headers, - }; - const response = await request(params).catch(e => e); - expect(response.status).toBe(400); - const text = JSON.parse(response.text); - expect(text.code).toBe(Parse.Error.INVALID_KEY_NAME); - expect(text.error).toBe( - 'Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.' - ); - }); - - it('denies direct database write wih prohibited keys', async () => { - const Config = require('../lib/Config'); - const config = Config.get(Parse.applicationId); - const user = { - objectId: '1234567890', - username: 'hello', - password: 'pass', - _session_token: 'abc', - foo: { _bsontype: 'Code', code: 'shell' }, - }; - await expectAsync(config.database.create('_User', user)).toBeRejectedWith( - new Parse.Error( - Parse.Error.INVALID_KEY_NAME, - 'Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.' - ) - ); - }); - - it('denies direct database update wih prohibited keys', async () => { - const Config = require('../lib/Config'); - const config = Config.get(Parse.applicationId); - const user = { - objectId: '1234567890', - username: 'hello', - password: 'pass', - _session_token: 'abc', - foo: { _bsontype: 'Code', code: 'shell' }, - }; - await expectAsync( - config.database.update('_User', { _id: user.objectId }, user) - ).toBeRejectedWith( - new Parse.Error( - Parse.Error.INVALID_KEY_NAME, - 'Prohibited keyword in request data: {"key":"_bsontype","value":"Code"}.' - ) - ); - }); - it('denies creating a hook with polluted data', async () => { const express = require('express'); const bodyParser = require('body-parser'); @@ -235,6 +170,32 @@ describe('Vulnerabilities', () => { await new Promise(resolve => server.close(resolve)); }); + it('allows BSON type code data in write request with custom denylist', async () => { + await reconfigureServer({ + requestKeywordDenylist: [], + }); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest', + }; + const params = { + headers: headers, + method: 'POST', + url: 'http://localhost:8378/1/classes/RCE', + body: JSON.stringify({ + obj: { + _bsontype: 'Code', + code: 'delete Object.prototype.evalFunctions', + }, + }), + }; + const response = await request(params).catch(e => e); + expect(response.status).toBe(201); + const text = JSON.parse(response.text); + expect(text.objectId).toBeDefined(); + }); + it('denies write request with custom denylist of key/value', async () => { await reconfigureServer({ requestKeywordDenylist: [{ key: 'a[K]ey', value: 'aValue[123]*' }], diff --git a/src/Adapters/Auth/AuthAdapter.js b/src/Adapters/Auth/AuthAdapter.js index e739df3f54..5b18c75170 100644 --- a/src/Adapters/Auth/AuthAdapter.js +++ b/src/Adapters/Auth/AuthAdapter.js @@ -21,9 +21,7 @@ export class AuthAdapter { * Usage policy * @type {AuthPolicy} */ - if (!this.policy) { - this.policy = 'default'; - } + this.policy = 'default'; } /** * @param appIds The specified app IDs in the configuration diff --git a/src/Adapters/Auth/apple.js b/src/Adapters/Auth/apple.js index 4fd1153b75..15b28ed203 100644 --- a/src/Adapters/Auth/apple.js +++ b/src/Adapters/Auth/apple.js @@ -3,6 +3,7 @@ const Parse = require('parse/node').Parse; const jwksClient = require('jwks-rsa'); +const util = require('util'); const jwt = require('jsonwebtoken'); const authUtils = require('./utils'); @@ -16,9 +17,11 @@ const getAppleKeyByKeyId = async (keyId, cacheMaxEntries, cacheMaxAge) => { cacheMaxAge, }); + const asyncGetSigningKeyFunction = util.promisify(client.getSigningKey); + let key; try { - key = await authUtils.getSigningKey(client, keyId); + key = await asyncGetSigningKeyFunction(keyId); } catch (error) { throw new Parse.Error( Parse.Error.OBJECT_NOT_FOUND, diff --git a/src/Adapters/Auth/facebook.js b/src/Adapters/Auth/facebook.js index 896fad0ff4..737657c8bd 100644 --- a/src/Adapters/Auth/facebook.js +++ b/src/Adapters/Auth/facebook.js @@ -2,6 +2,7 @@ const Parse = require('parse/node').Parse; const crypto = require('crypto'); const jwksClient = require('jwks-rsa'); +const util = require('util'); const jwt = require('jsonwebtoken'); const httpsRequest = require('./httpsRequest'); const authUtils = require('./utils'); @@ -59,9 +60,11 @@ const getFacebookKeyByKeyId = async (keyId, cacheMaxEntries, cacheMaxAge) => { cacheMaxAge, }); + const asyncGetSigningKeyFunction = util.promisify(client.getSigningKey); + let key; try { - key = await authUtils.getSigningKey(client, keyId); + key = await asyncGetSigningKeyFunction(keyId); } catch (error) { throw new Parse.Error( Parse.Error.OBJECT_NOT_FOUND, diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index da65b24ba5..2defcb0dc0 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -9,7 +9,6 @@ const facebook = require('./facebook'); const instagram = require('./instagram'); const linkedin = require('./linkedin'); const meetup = require('./meetup'); -import mfa from './mfa'; const google = require('./google'); const github = require('./github'); const twitter = require('./twitter'); @@ -45,7 +44,6 @@ const providers = { instagram, linkedin, meetup, - mfa, google, github, twitter, @@ -77,11 +75,7 @@ function authDataValidator(provider, adapter, appIds, options) { if (appIds && typeof adapter.validateAppId === 'function') { await Promise.resolve(adapter.validateAppId(appIds, authData, options, requestObject)); } - if ( - adapter.policy && - !authAdapterPolicies[adapter.policy] && - typeof adapter.policy !== 'function' - ) { + if (adapter.policy && !authAdapterPolicies[adapter.policy]) { throw new Parse.Error( Parse.Error.OTHER_CAUSE, 'AuthAdapter policy is not configured correctly. The value must be either "solo", "additional", "default" or undefined (will be handled as "default")' @@ -231,20 +225,17 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) { if (!authAdapter) { return; } - const { adapter, providerOptions } = authAdapter; - const afterFind = adapter.afterFind; + 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.call( - adapter, - requestObject, - authData[provider], - providerOptions - ); + const result = afterFind(requestObject, authData[provider], providerOptions); if (result) { authData[provider] = result; } diff --git a/src/Adapters/Auth/ldap.js b/src/Adapters/Auth/ldap.js index 7cea9e3f2b..8ea735698f 100644 --- a/src/Adapters/Auth/ldap.js +++ b/src/Adapters/Auth/ldap.js @@ -78,7 +78,7 @@ function searchForGroup(client, options, id, resolve, reject) { return reject(new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'LDAP group search failed')); } res.on('searchEntry', entry => { - if (entry.object.cn === options.groupCn) { + if (entry.pojo.attributes.find(obj => obj.type === 'cn').values.includes(options.groupCn)) { found = true; client.unbind(); client.destroy(); diff --git a/src/Adapters/Auth/mfa.js b/src/Adapters/Auth/mfa.js deleted file mode 100644 index a88eda99e7..0000000000 --- a/src/Adapters/Auth/mfa.js +++ /dev/null @@ -1,213 +0,0 @@ -import { TOTP, Secret } from 'otpauth'; -import { randomString } from '../../cryptoUtils'; -import AuthAdapter from './AuthAdapter'; -class MFAAdapter extends AuthAdapter { - validateOptions(opts) { - const validOptions = opts.options; - if (!Array.isArray(validOptions)) { - throw 'mfa.options must be an array'; - } - this.sms = validOptions.includes('SMS'); - this.totp = validOptions.includes('TOTP'); - if (!this.sms && !this.totp) { - throw 'mfa.options must include SMS or TOTP'; - } - const digits = opts.digits || 6; - const period = opts.period || 30; - if (typeof digits !== 'number') { - throw 'mfa.digits must be a number'; - } - if (typeof period !== 'number') { - throw 'mfa.period must be a number'; - } - if (digits < 4 || digits > 10) { - throw 'mfa.digits must be between 4 and 10'; - } - if (period < 10) { - throw 'mfa.period must be greater than 10'; - } - const sendSMS = opts.sendSMS; - if (this.sms && typeof sendSMS !== 'function') { - throw 'mfa.sendSMS callback must be defined when using SMS OTPs'; - } - this.smsCallback = sendSMS; - this.digits = digits; - this.period = period; - this.algorithm = opts.algorithm || 'SHA1'; - } - validateSetUp(mfaData) { - if (mfaData.mobile && this.sms) { - return this.setupMobileOTP(mfaData.mobile); - } - if (this.totp) { - return this.setupTOTP(mfaData); - } - throw 'Invalid MFA data'; - } - async validateLogin(loginData, _, req) { - const saveResponse = { - doNotSave: true, - }; - const token = loginData.token; - const auth = req.original.get('authData') || {}; - const { secret, recovery, mobile, token: saved, expiry } = auth.mfa || {}; - if (this.sms && mobile) { - if (token === 'request') { - const { token: sendToken, expiry } = await this.sendSMS(mobile); - auth.mfa.token = sendToken; - auth.mfa.expiry = expiry; - req.object.set('authData', auth); - await req.object.save(null, { useMasterKey: true }); - throw 'Please enter the token'; - } - if (!saved || token !== saved) { - throw 'Invalid MFA token 1'; - } - if (new Date() > expiry) { - throw 'Invalid MFA token 2'; - } - delete auth.mfa.token; - delete auth.mfa.expiry; - return { - save: auth.mfa, - }; - } - if (this.totp) { - if (typeof token !== 'string') { - throw 'Invalid MFA token'; - } - if (!secret) { - return saveResponse; - } - if (recovery[0] === token || recovery[1] === token) { - return saveResponse; - } - const totp = new TOTP({ - algorithm: this.algorithm, - digits: this.digits, - period: this.period, - secret: Secret.fromBase32(secret), - }); - const valid = totp.validate({ - token, - }); - if (valid === null) { - throw 'Invalid MFA token'; - } - } - return saveResponse; - } - async validateUpdate(authData, _, req) { - if (req.master) { - return; - } - if (authData.mobile && this.sms) { - if (!authData.token) { - throw 'MFA is already set up on this account'; - } - return this.confirmSMSOTP(authData, req.original.get('authData')?.mfa || {}); - } - if (this.totp) { - await this.validateLogin({ token: authData.old }, null, req); - return this.validateSetUp(authData); - } - throw 'Invalid MFA data'; - } - afterFind(req, authData) { - if (req.master) { - return; - } - if (this.totp && authData.secret) { - return { - status: 'enabled', - }; - } - if (this.sms && authData.mobile) { - return { - status: 'enabled', - }; - } - return { - status: 'disabled', - }; - } - - policy(req, auth) { - if (this.sms && auth?.pending && Object.keys(auth).length === 1) { - return 'default'; - } - return 'additional'; - } - - async setupMobileOTP(mobile) { - const { token, expiry } = await this.sendSMS(mobile); - return { - save: { - pending: { - [mobile]: { - token, - expiry, - }, - }, - }, - }; - } - - async sendSMS(mobile) { - if (!/^[+]*[(]{0,1}[0-9]{1,3}[)]{0,1}[-\s\./0-9]*$/g.test(mobile)) { - throw 'Invalid mobile number.'; - } - let token = ''; - while (token.length < this.digits) { - token += randomString(10).replace(/\D/g, ''); - } - token = token.substring(0, this.digits); - await Promise.resolve(this.smsCallback(token, mobile)); - const expiry = new Date(new Date().getTime() + this.period * 1000); - return { token, expiry }; - } - - async confirmSMSOTP(inputData, authData) { - const { mobile, token } = inputData; - if (!authData.pending?.[mobile]) { - throw 'This number is not pending'; - } - const pendingData = authData.pending[mobile]; - if (token !== pendingData.token) { - throw 'Invalid MFA token'; - } - if (new Date() > pendingData.expiry) { - throw 'Invalid MFA token'; - } - delete authData.pending[mobile]; - authData.mobile = mobile; - return { - save: authData, - }; - } - - setupTOTP(mfaData) { - const { secret, token } = mfaData; - if (!secret || !token || secret.length < 20) { - throw 'Invalid MFA data'; - } - const totp = new TOTP({ - algorithm: this.algorithm, - digits: this.digits, - period: this.period, - secret: Secret.fromBase32(secret), - }); - const valid = totp.validate({ - token, - }); - if (valid === null) { - throw 'Invalid MFA token'; - } - const recovery = [randomString(30), randomString(30)]; - return { - response: { recovery: recovery.join(', ') }, - save: { secret, recovery }, - }; - } -} -export default new MFAAdapter(); diff --git a/src/Adapters/Auth/utils.js b/src/Adapters/Auth/utils.js index 0d4d7cd8a2..c50adaba79 100644 --- a/src/Adapters/Auth/utils.js +++ b/src/Adapters/Auth/utils.js @@ -1,5 +1,4 @@ const jwt = require('jsonwebtoken'); -const util = require('util'); const Parse = require('parse/node').Parse; const getHeaderFromToken = token => { const decodedToken = jwt.decode(token, { complete: true }); @@ -9,16 +8,6 @@ const getHeaderFromToken = token => { return decodedToken.header; }; - -/** - * Returns the signing key from a JWKS client. - * @param {Object} client The JWKS client. - * @param {String} key The kid. - */ -async function getSigningKey(client, key) { - return util.promisify(client.getSigningKey)(key); -} module.exports = { getHeaderFromToken, - getSigningKey, }; diff --git a/src/Adapters/Cache/RedisCacheAdapter.js b/src/Adapters/Cache/RedisCacheAdapter.js index a0345a1101..eba16694e3 100644 --- a/src/Adapters/Cache/RedisCacheAdapter.js +++ b/src/Adapters/Cache/RedisCacheAdapter.js @@ -17,10 +17,6 @@ export class RedisCacheAdapter { this.ttl = isValidTTL(ttl) ? ttl : DEFAULT_REDIS_TTL; this.client = createClient(redisCtx); this.queue = new KeyPromiseQueue(); - this.client.on('error', err => { logger.error('RedisCacheAdapter client error', { error: err }) }); - this.client.on('connect', () => {}); - this.client.on('reconnecting', () => {}); - this.client.on('ready', () => {}); } async connect() { diff --git a/src/Adapters/Files/GridFSBucketAdapter.js b/src/Adapters/Files/GridFSBucketAdapter.js index 76a8f25d1b..451165789d 100644 --- a/src/Adapters/Files/GridFSBucketAdapter.js +++ b/src/Adapters/Files/GridFSBucketAdapter.js @@ -28,11 +28,7 @@ export class GridFSBucketAdapter extends FilesAdapter { this._algorithm = 'aes-256-gcm'; this._encryptionKey = encryptionKey !== undefined - ? crypto - .createHash('sha256') - .update(String(encryptionKey)) - .digest('base64') - .substring(0, 32) + ? crypto.createHash('sha256').update(String(encryptionKey)).digest('base64').substr(0, 32) : null; const defaultMongoOptions = { useNewUrlParser: true, @@ -142,8 +138,8 @@ export class GridFSBucketAdapter extends FilesAdapter { } async rotateEncryptionKey(options = {}) { - let fileNames = []; - let oldKeyFileAdapter = {}; + var fileNames = []; + var oldKeyFileAdapter = {}; const bucket = await this._getBucket(); if (options.oldKey !== undefined) { oldKeyFileAdapter = new GridFSBucketAdapter( @@ -162,22 +158,51 @@ export class GridFSBucketAdapter extends FilesAdapter { fileNames.push(file.filename); }); } - let fileNamesNotRotated = fileNames; - const fileNamesRotated = []; - for (const fileName of fileNames) { - try { - const plainTextData = await oldKeyFileAdapter.getFileData(fileName); - // Overwrite file with data encrypted with new key - await this.createFile(fileName, plainTextData); - fileNamesRotated.push(fileName); - fileNamesNotRotated = fileNamesNotRotated.filter(function (value) { - return value !== fileName; - }); - } catch (err) { - continue; - } - } - return { rotated: fileNamesRotated, notRotated: fileNamesNotRotated }; + return new Promise(resolve => { + var fileNamesNotRotated = fileNames; + var fileNamesRotated = []; + var fileNameTotal = fileNames.length; + var fileNameIndex = 0; + fileNames.forEach(fileName => { + oldKeyFileAdapter + .getFileData(fileName) + .then(plainTextData => { + //Overwrite file with data encrypted with new key + this.createFile(fileName, plainTextData) + .then(() => { + fileNamesRotated.push(fileName); + fileNamesNotRotated = fileNamesNotRotated.filter(function (value) { + return value !== fileName; + }); + fileNameIndex += 1; + if (fileNameIndex == fileNameTotal) { + resolve({ + rotated: fileNamesRotated, + notRotated: fileNamesNotRotated, + }); + } + }) + .catch(() => { + fileNameIndex += 1; + if (fileNameIndex == fileNameTotal) { + resolve({ + rotated: fileNamesRotated, + notRotated: fileNamesNotRotated, + }); + } + }); + }) + .catch(() => { + fileNameIndex += 1; + if (fileNameIndex == fileNameTotal) { + resolve({ + rotated: fileNamesRotated, + notRotated: fileNamesNotRotated, + }); + } + }); + }); + }); } getFileLocation(config, filename) { diff --git a/src/Adapters/Storage/Mongo/MongoCollection.js b/src/Adapters/Storage/Mongo/MongoCollection.js index 48de677c2e..f3f089f0f1 100644 --- a/src/Adapters/Storage/Mongo/MongoCollection.js +++ b/src/Adapters/Storage/Mongo/MongoCollection.js @@ -160,10 +160,18 @@ export default class MongoCollection { } _ensureSparseUniqueIndexInBackground(indexRequest) { - return this._mongoCollection.createIndex(indexRequest, { - unique: true, - background: true, - sparse: true, + return new Promise((resolve, reject) => { + this._mongoCollection.createIndex( + indexRequest, + { unique: true, background: true, sparse: true }, + error => { + if (error) { + reject(error); + } else { + resolve(); + } + } + ); }); } diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 53d1bc4959..2f59819895 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -172,6 +172,7 @@ export class MongoStorageAdapter implements StorageAdapter { // parsing and re-formatting causes the auth value (if there) to get URI // encoded const encodedUri = formatUrl(parseUrl(this._uri)); + this.connectionPromise = MongoClient.connect(encodedUri, this._mongoOptions) .then(client => { // Starting mongoDB 3.0, the MongoClient.connect don't return a DB anymore but a client @@ -686,8 +687,13 @@ export class MongoStorageAdapter implements StorageAdapter { }; return this._adaptiveCollection(className) - .then(collection => - collection._mongoCollection.createIndex(indexCreationRequest, indexOptions) + .then( + collection => + new Promise((resolve, reject) => + collection._mongoCollection.createIndex(indexCreationRequest, indexOptions, error => + error ? reject(error) : resolve() + ) + ) ) .catch(err => this.handleError(err)); } diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 336d9affc9..6f6811cec3 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -457,7 +457,6 @@ const parseObjectKeyValueToMongoObjectKeyValue = (restKey, restValue, schema) => ); } value = mapValues(restValue, transformInteriorValue); - return { key: restKey, value }; }; @@ -987,13 +986,6 @@ function transformUpdateOperator({ __op, amount, objects }, flatten) { return { __op: '$inc', arg: amount }; } - case 'SetOnInsert': - if (flatten) { - return amount; - } else { - return { __op: '$setOnInsert', arg: amount }; - } - case 'Add': case 'AddUnique': if (!(objects instanceof Array)) { diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 3ad59ec77f..3e8e867799 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -231,7 +231,7 @@ const transformAggregateField = fieldName => { if (fieldName === '$_updated_at') { return 'updatedAt'; } - return fieldName.substring(1); + return fieldName.substr(1); }; const validateKeys = object => { @@ -1921,14 +1921,14 @@ export class PostgresStorageAdapter implements StorageAdapter { }; } if (object[fieldName] && schema.fields[fieldName].type === 'Polygon') { - let coords = new String(object[fieldName]); - coords = coords.substring(2, coords.length - 2).split('),('); - const updatedCoords = coords.map(point => { + let coords = object[fieldName]; + coords = coords.substr(2, coords.length - 4).split('),('); + coords = coords.map(point => { return [parseFloat(point.split(',')[1]), parseFloat(point.split(',')[0])]; }); object[fieldName] = { __type: 'Polygon', - coordinates: updatedCoords, + coordinates: coords, }; } if (object[fieldName] && schema.fields[fieldName].type === 'File') { @@ -2634,7 +2634,7 @@ function literalizeRegexPart(s: string) { const result1: any = s.match(matcher1); if (result1 && result1.length > 1 && result1.index > -1) { // process regex that has a beginning and an end specified for the literal text - const prefix = s.substring(0, result1.index); + const prefix = s.substr(0, result1.index); const remaining = result1[1]; return literalizeRegexPart(prefix) + createLiteralRegex(remaining); @@ -2644,7 +2644,7 @@ function literalizeRegexPart(s: string) { const matcher2 = /\\Q((?!\\E).*)$/; const result2: any = s.match(matcher2); if (result2 && result2.length > 1 && result2.index > -1) { - const prefix = s.substring(0, result2.index); + const prefix = s.substr(0, result2.index); const remaining = result2[1]; return literalizeRegexPart(prefix) + createLiteralRegex(remaining); diff --git a/src/Auth.js b/src/Auth.js index f21ba96c6c..96c99cbb1d 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -1,6 +1,7 @@ const Parse = require('parse/node'); import { isDeepStrictEqual } from 'util'; import { getRequestObject, resolveError } from './triggers'; +import Deprecator from './Deprecator/Deprecator'; import { logger } from './logger'; import RestQuery from './RestQuery'; import RestWrite from './RestWrite'; @@ -76,16 +77,13 @@ const renewSessionIfNeeded = async ({ config, session, sessionToken }) => { throttle[sessionToken] = setTimeout(async () => { try { if (!session) { - const query = await RestQuery({ - method: RestQuery.Method.get, + const { results } = await new RestQuery( config, - auth: master(config), - runBeforeFind: false, - className: '_Session', - restWhere: { sessionToken }, - restOptions: { limit: 1 }, - }); - const { results } = await query.execute(); + master(config), + '_Session', + { sessionToken }, + { limit: 1 } + ).execute(); session = results[0]; } const lastUpdated = new Date(session?.updatedAt); @@ -142,15 +140,7 @@ const getAuthForSessionToken = async function ({ include: 'user', }; const RestQuery = require('./RestQuery'); - const query = await RestQuery({ - method: RestQuery.Method.get, - config, - runBeforeFind: false, - auth: master(config), - className: '_Session', - restWhere: { sessionToken }, - restOptions, - }); + const query = new RestQuery(config, master(config), '_Session', { sessionToken }, restOptions); results = (await query.execute()).results; } else { results = ( @@ -189,20 +179,12 @@ const getAuthForSessionToken = async function ({ }); }; -var getAuthForLegacySessionToken = async function ({ config, sessionToken, installationId }) { +var getAuthForLegacySessionToken = function ({ config, sessionToken, installationId }) { var restOptions = { limit: 1, }; const RestQuery = require('./RestQuery'); - var query = await RestQuery({ - method: RestQuery.Method.get, - config, - runBeforeFind: false, - auth: master(config), - className: '_User', - restWhere: { _session_token: sessionToken }, - restOptions, - }); + var query = new RestQuery(config, master(config), '_User', { sessionToken }, restOptions); return query.execute().then(response => { var results = response.results; if (results.length !== 1) { @@ -247,15 +229,9 @@ Auth.prototype.getRolesForUser = async function () { }, }; const RestQuery = require('./RestQuery'); - const query = await RestQuery({ - method: RestQuery.Method.find, - runBeforeFind: false, - config: this.config, - auth: master(this.config), - className: '_Role', - restWhere, - }); - await query.each(result => results.push(result)); + await new RestQuery(this.config, master(this.config), '_Role', restWhere, {}).each(result => + results.push(result) + ); } else { await new Parse.Query(Parse.Role) .equalTo('users', this.user) @@ -347,15 +323,9 @@ Auth.prototype.getRolesByIds = async function (ins) { }); const restWhere = { roles: { $in: roles } }; const RestQuery = require('./RestQuery'); - const query = await RestQuery({ - method: RestQuery.Method.find, - config: this.config, - runBeforeFind: false, - auth: master(this.config), - className: '_Role', - restWhere, - }); - await query.each(result => results.push(result)); + await new RestQuery(this.config, master(this.config), '_Role', restWhere, {}).each(result => + results.push(result) + ); } return results; }; @@ -437,7 +407,6 @@ const hasMutatedAuthData = (authData, userAuthData) => { }; const checkIfUserHasProvidedConfiguredProvidersForLogin = ( - req = {}, authData = {}, userAuthData = {}, config @@ -461,16 +430,7 @@ const checkIfUserHasProvidedConfiguredProvidersForLogin = ( const additionProvidersNotFound = []; const hasProvidedAtLeastOneAdditionalProvider = savedUserProviders.some(provider => { - let policy = provider.adapter.policy; - if (typeof policy === 'function') { - const requestObject = { - ip: req.config.ip, - user: req.auth.user, - master: req.auth.isMaster, - }; - policy = policy.call(provider.adapter, requestObject, userAuthData[provider.name]); - } - if (policy === 'additional') { + if (provider && provider.adapter && provider.adapter.policy === 'additional') { if (authData[provider.name]) { return true; } else { @@ -507,8 +467,14 @@ const handleAuthDataValidation = async (authData, req, foundUser) => { await user.fetch({ useMasterKey: true }); } - const { updatedObject } = req.buildParseObjects(); - const requestObject = getRequestObject(undefined, req.auth, updatedObject, user, req.config); + const { originalObject, updatedObject } = req.buildParseObjects(); + const requestObject = getRequestObject( + undefined, + req.auth, + updatedObject, + originalObject || user, + req.config + ); // Perform validation as step-by-step pipeline for better error consistency // and also to avoid to trigger a provider (like OTP SMS) if another one fails const acc = { authData: {}, authDataResponse: {} }; @@ -522,6 +488,12 @@ const handleAuthDataValidation = async (authData, req, foundUser) => { } const { validator } = req.config.authDataManager.getValidatorForProvider(provider); const authProvider = (req.config.auth || {})[provider] || {}; + if (authProvider.enabled == null) { + Deprecator.logRuntimeDeprecation({ + usage: `Using the authentication adapter "${provider}" without explicitly enabling it`, + solution: `Enable the authentication adapter by setting the Parse Server option "auth.${provider}.enabled: true".`, + }); + } if (!validator || authProvider.enabled === false) { throw new Parse.Error( Parse.Error.UNSUPPORTED_SERVICE, diff --git a/src/Config.js b/src/Config.js index 0e8cdda246..5e3a49bb35 100644 --- a/src/Config.js +++ b/src/Config.js @@ -7,7 +7,6 @@ import net from 'net'; import AppCache from './cache'; import DatabaseController from './Controllers/DatabaseController'; import { logLevels as validLogLevels } from './Controllers/LoggerController'; -import { version } from '../package.json'; import { AccountLockoutOptions, DatabaseOptions, @@ -26,7 +25,7 @@ function removeTrailingSlash(str) { return str; } if (str.endsWith('/')) { - str = str.substring(0, str.length - 1); + str = str.substr(0, str.length - 1); } return str; } @@ -51,7 +50,6 @@ export class Config { config.generateEmailVerifyTokenExpiresAt = config.generateEmailVerifyTokenExpiresAt.bind( config ); - config.version = version; return config; } diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 5975e94053..e3ac5723ab 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -279,9 +279,6 @@ const flattenUpdateOperatorsForCreate = object => { } object[key] = object[key].amount; break; - case 'SetOnInsert': - object[key] = object[key].amount; - break; case 'Add': if (!(object[key].objects instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array'); @@ -368,22 +365,6 @@ const relationSchema = { fields: { relatedId: { type: 'String' }, owningId: { type: 'String' } }, }; -const convertEmailToLowercase = (object, className, options) => { - if (className === '_User' && options.convertEmailToLowercase) { - if (typeof object['email'] === 'string') { - object['email'] = object['email'].toLowerCase(); - } - } -}; - -const convertUsernameToLowercase = (object, className, options) => { - if (className === '_User' && options.convertUsernameToLowercase) { - if (typeof object['username'] === 'string') { - object['username'] = object['username'].toLowerCase(); - } - } -}; - class DatabaseController { adapter: StorageAdapter; schemaCache: any; @@ -494,11 +475,6 @@ class DatabaseController { validateOnly: boolean = false, validSchemaController: SchemaController.SchemaController ): Promise { - try { - Utils.checkProhibitedKeywords(this.options, update); - } catch (error) { - return Promise.reject(new Parse.Error(Parse.Error.INVALID_KEY_NAME, error)); - } const originalQuery = query; const originalUpdate = update; // Make a copy of the object, so we don't mutate the incoming data. @@ -589,8 +565,6 @@ class DatabaseController { } } update = transformObjectACL(update); - convertEmailToLowercase(update, className, this.options); - convertUsernameToLowercase(update, className, this.options); transformAuthData(className, update, schema); if (validateOnly) { return this.adapter.find(className, schema, query, {}).then(result => { @@ -831,17 +805,10 @@ class DatabaseController { validateOnly: boolean = false, validSchemaController: SchemaController.SchemaController ): Promise { - try { - Utils.checkProhibitedKeywords(this.options, object); - } catch (error) { - return Promise.reject(new Parse.Error(Parse.Error.INVALID_KEY_NAME, error)); - } // Make a copy of the object, so we don't mutate the incoming data. const originalObject = object; object = transformObjectACL(object); - convertEmailToLowercase(object, className, this.options); - convertUsernameToLowercase(object, className, this.options); object.createdAt = { iso: object.createdAt, __type: 'Date' }; object.updatedAt = { iso: object.updatedAt, __type: 'Date' }; @@ -1235,7 +1202,7 @@ class DatabaseController { keys, readPreference, hint, - caseInsensitive: this.options.enableCollationCaseComparison ? false : caseInsensitive, + caseInsensitive, explain, }; Object.keys(sort).forEach(fieldName => { @@ -1739,27 +1706,31 @@ class DatabaseController { throw error; }); - if (!this.options.enableCollationCaseComparison) { - await this.adapter - .ensureIndex('_User', requiredUserFields, ['username'], 'case_insensitive_username', true) - .catch(error => { - logger.warn('Unable to create case insensitive username index: ', error); - throw error; - }); - - await this.adapter - .ensureIndex('_User', requiredUserFields, ['email'], 'case_insensitive_email', true) - .catch(error => { - logger.warn('Unable to create case insensitive email index: ', error); - throw error; - }); - } + await this.adapter + .ensureIndex('_User', requiredUserFields, ['username'], 'case_insensitive_username', true) + .catch(error => { + logger.warn('Unable to create case insensitive username index: ', error); + throw error; + }); + await this.adapter + .ensureIndex('_User', requiredUserFields, ['username'], 'case_insensitive_username', true) + .catch(error => { + logger.warn('Unable to create case insensitive username index: ', error); + throw error; + }); await this.adapter.ensureUniqueness('_User', requiredUserFields, ['email']).catch(error => { logger.warn('Unable to ensure uniqueness for user email addresses: ', error); throw error; }); + await this.adapter + .ensureIndex('_User', requiredUserFields, ['email'], 'case_insensitive_email', true) + .catch(error => { + logger.warn('Unable to create case insensitive email index: ', error); + throw error; + }); + await this.adapter.ensureUniqueness('_Role', requiredRoleFields, ['name']).catch(error => { logger.warn('Unable to ensure uniqueness for role name: ', error); throw error; @@ -1842,7 +1813,7 @@ class DatabaseController { keyUpdate && typeof keyUpdate === 'object' && keyUpdate.__op && - ['Add', 'AddUnique', 'Remove', 'Increment', 'SetOnInsert'].indexOf(keyUpdate.__op) > -1 + ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1 ) { // only valid ops that produce an actionable result // the op may have happened on a keypath diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index 04fb5c4fd0..1a5b9bf491 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -58,16 +58,9 @@ export class PushController { // Force filtering on only valid device tokens const updateWhere = applyDeviceTokenExists(where); - badgeUpdate = async () => { + badgeUpdate = () => { // Build a real RestQuery so we can use it in RestWrite - const restQuery = await RestQuery({ - method: RestQuery.Method.find, - config, - runBeforeFind: false, - auth: master(config), - className: '_Installation', - restWhere: updateWhere, - }); + const restQuery = new RestQuery(config, master(config), '_Installation', updateWhere); return restQuery.buildRestWhere().then(() => { const write = new RestWrite( config, diff --git a/src/Controllers/UserController.js b/src/Controllers/UserController.js index 0e8e18ae7d..6871add987 100644 --- a/src/Controllers/UserController.js +++ b/src/Controllers/UserController.js @@ -32,35 +32,23 @@ export class UserController extends AdaptableController { } get shouldVerifyEmails() { - return (this.config || this.options).verifyUserEmails; + return this.options.verifyUserEmails; } - async setEmailVerifyToken(user, req, storage = {}) { - const shouldSendEmail = - this.shouldVerifyEmails === true || - (typeof this.shouldVerifyEmails === 'function' && - (await Promise.resolve(this.shouldVerifyEmails(req))) === true); - if (!shouldSendEmail) { - return false; - } - storage.sendVerificationEmail = true; - user._email_verify_token = randomString(25); - if ( - !storage.fieldsChangedByTrigger || - !storage.fieldsChangedByTrigger.includes('emailVerified') - ) { + setEmailVerifyToken(user) { + if (this.shouldVerifyEmails) { + user._email_verify_token = randomString(25); user.emailVerified = false; - } - if (this.config.emailVerifyTokenValidityDuration) { - user._email_verify_token_expires_at = Parse._encode( - this.config.generateEmailVerifyTokenExpiresAt() - ); + if (this.config.emailVerifyTokenValidityDuration) { + user._email_verify_token_expires_at = Parse._encode( + this.config.generateEmailVerifyTokenExpiresAt() + ); + } } - return true; } - async verifyEmail(username, token) { + verifyEmail(username, token) { if (!this.shouldVerifyEmails) { // Trying to verify email when not enabled // TODO: Better error here. @@ -82,14 +70,8 @@ export class UserController extends AdaptableController { updateFields._email_verify_token_expires_at = { __op: 'Delete' }; } const maintenanceAuth = Auth.maintenance(this.config); - var findUserForEmailVerification = await RestQuery({ - method: RestQuery.Method.get, - config: this.config, - auth: maintenanceAuth, - className: '_User', - restWhere: { - username, - }, + var findUserForEmailVerification = new RestQuery(this.config, maintenanceAuth, '_User', { + username, }); return findUserForEmailVerification.execute().then(result => { if (result.results.length && result.results[0].emailVerified) { @@ -128,7 +110,10 @@ export class UserController extends AdaptableController { }); } - async getUserIfNeeded(user) { + getUserIfNeeded(user) { + if (user.username && user.email) { + return Promise.resolve(user); + } var where = {}; if (user.username) { where.username = user.username; @@ -137,55 +122,36 @@ export class UserController extends AdaptableController { where.email = user.email; } - var query = await RestQuery({ - method: RestQuery.Method.get, - config: this.config, - runBeforeFind: false, - auth: Auth.master(this.config), - className: '_User', - restWhere: where, + var query = new RestQuery(this.config, Auth.master(this.config), '_User', where); + return query.execute().then(function (result) { + if (result.results.length != 1) { + throw undefined; + } + return result.results[0]; }); - const result = await query.execute(); - if (result.results.length != 1) { - throw undefined; - } - return result.results[0]; } - async sendVerificationEmail(user, req) { + sendVerificationEmail(user) { if (!this.shouldVerifyEmails) { return; } const token = encodeURIComponent(user._email_verify_token); - // We may need to fetch the user in case of update email; only use the `fetchedUser` - // from this point onwards; do not use the `user` as it may not contain all fields. - const fetchedUser = await this.getUserIfNeeded(user); - let shouldSendEmail = this.config.sendUserEmailVerification; - if (typeof shouldSendEmail === 'function') { - const response = await Promise.resolve( - this.config.sendUserEmailVerification({ - user: Parse.Object.fromJSON({ className: '_User', ...fetchedUser }), - master: req.auth?.isMaster, - }) - ); - shouldSendEmail = !!response; - } - if (!shouldSendEmail) { - return; - } - const username = encodeURIComponent(fetchedUser.username); - - const link = buildEmailLink(this.config.verifyEmailURL, username, token, this.config); - const options = { - appName: this.config.appName, - link: link, - user: inflate('_User', fetchedUser), - }; - if (this.adapter.sendVerificationEmail) { - this.adapter.sendVerificationEmail(options); - } else { - this.adapter.sendMail(this.defaultVerificationEmail(options)); - } + // We may need to fetch the user in case of update email + this.getUserIfNeeded(user).then(user => { + const username = encodeURIComponent(user.username); + + const link = buildEmailLink(this.config.verifyEmailURL, username, token, this.config); + const options = { + appName: this.config.appName, + link: link, + user: inflate('_User', user), + }; + if (this.adapter.sendVerificationEmail) { + this.adapter.sendVerificationEmail(options); + } else { + this.adapter.sendMail(this.defaultVerificationEmail(options)); + } + }); } /** @@ -194,7 +160,7 @@ export class UserController extends AdaptableController { * @param user * @returns {*} */ - async regenerateEmailVerifyToken(user, master, installationId, ip) { + regenerateEmailVerifyToken(user) { const { _email_verify_token } = user; let { _email_verify_token_expires_at } = user; if (_email_verify_token_expires_at && _email_verify_token_expires_at.__type === 'Date') { @@ -206,30 +172,21 @@ export class UserController extends AdaptableController { _email_verify_token && new Date() < new Date(_email_verify_token_expires_at) ) { - return Promise.resolve(true); - } - const shouldSend = await this.setEmailVerifyToken(user, { - object: Parse.User.fromJSON(Object.assign({ className: '_User' }, user)), - master, - installationId, - ip, - resendRequest: true - }); - if (!shouldSend) { - return; + return Promise.resolve(); } + this.setEmailVerifyToken(user); return this.config.database.update('_User', { username: user.username }, user); } - async resendVerificationEmail(username, req) { - const aUser = await this.getUserIfNeeded({ username: username }); - if (!aUser || aUser.emailVerified) { - throw undefined; - } - const generate = await this.regenerateEmailVerifyToken(aUser, req.auth?.isMaster, req.auth?.installationId, req.ip); - if (generate) { - this.sendVerificationEmail(aUser, req); - } + resendVerificationEmail(username) { + return this.getUserIfNeeded({ username: username }).then(aUser => { + if (!aUser || aUser.emailVerified) { + throw undefined; + } + return this.regenerateEmailVerifyToken(aUser).then(() => { + this.sendVerificationEmail(aUser); + }); + }); } setPasswordResetToken(email) { diff --git a/src/Deprecator/Deprecations.js b/src/Deprecator/Deprecations.js index 0e901dfda4..0afd98ff0c 100644 --- a/src/Deprecator/Deprecations.js +++ b/src/Deprecator/Deprecations.js @@ -17,5 +17,5 @@ */ module.exports = [ { optionKey: 'allowClientClassCreation', changeNewDefault: 'false' }, - { optionKey: 'encodeParseObjectInCloudFunction', changeNewDefault: 'true' }, + { optionKey: 'allowExpiredAuthDataToken', changeNewDefault: 'false' }, ]; diff --git a/src/GraphQL/loaders/parseClassMutations.js b/src/GraphQL/loaders/parseClassMutations.js index aa15f70505..41d7c09dde 100644 --- a/src/GraphQL/loaders/parseClassMutations.js +++ b/src/GraphQL/loaders/parseClassMutations.js @@ -82,7 +82,6 @@ const load = function (parseGraphQLSchema, parseClass, parseClassConfig: ?ParseG const parseFields = await transformTypes('create', fields, { className, parseGraphQLSchema, - originalFields: args.fields, req: { config, auth, info }, }); @@ -191,7 +190,6 @@ const load = function (parseGraphQLSchema, parseClass, parseClassConfig: ?ParseG const parseFields = await transformTypes('update', fields, { className, parseGraphQLSchema, - originalFields: args.fields, req: { config, auth, info }, }); diff --git a/src/GraphQL/loaders/usersMutations.js b/src/GraphQL/loaders/usersMutations.js index 58236cdbd4..183268a191 100644 --- a/src/GraphQL/loaders/usersMutations.js +++ b/src/GraphQL/loaders/usersMutations.js @@ -38,7 +38,6 @@ const load = parseGraphQLSchema => { const parseFields = await transformTypes('create', fields, { className: '_User', parseGraphQLSchema, - originalFields: args.fields, req: { config, auth, info }, }); @@ -115,7 +114,6 @@ const load = parseGraphQLSchema => { const parseFields = await transformTypes('create', fields, { className: '_User', parseGraphQLSchema, - originalFields: args.fields, req: { config, auth, info }, }); diff --git a/src/GraphQL/transformers/mutation.js b/src/GraphQL/transformers/mutation.js index 17dd6a8d4b..5b72d6f05d 100644 --- a/src/GraphQL/transformers/mutation.js +++ b/src/GraphQL/transformers/mutation.js @@ -7,7 +7,7 @@ import * as objectsMutations from '../helpers/objectsMutations'; const transformTypes = async ( inputType: 'create' | 'update', fields, - { className, parseGraphQLSchema, req, originalFields } + { className, parseGraphQLSchema, req } ) => { const { classGraphQLCreateType, @@ -44,16 +44,13 @@ const transformTypes = async ( fields[field] = transformers.polygon(fields[field]); break; case inputTypeField.type === defaultGraphQLTypes.FILE_INPUT: - // Use `originalFields` to handle file upload since fields are a deepcopy and do not - // keep the file object - fields[field] = await transformers.file(originalFields[field], req); + fields[field] = await transformers.file(fields[field], req); break; case parseClass.fields[field].type === 'Relation': fields[field] = await transformers.relation( parseClass.fields[field].targetClass, field, fields[field], - originalFields[field], parseGraphQLSchema, req ); @@ -67,7 +64,6 @@ const transformTypes = async ( parseClass.fields[field].targetClass, field, fields[field], - originalFields[field], parseGraphQLSchema, req ); @@ -139,14 +135,7 @@ const transformers = { } return parseACL; }, - relation: async ( - targetClass, - field, - value, - originalValue, - parseGraphQLSchema, - { config, auth, info } - ) => { + relation: async (targetClass, field, value, parseGraphQLSchema, { config, auth, info }) => { if (Object.keys(value).length === 0) throw new Parse.Error( Parse.Error.INVALID_POINTER, @@ -162,10 +151,9 @@ const transformers = { if (value.createAndAdd) { nestedObjectsToAdd = ( await Promise.all( - value.createAndAdd.map(async (input, i) => { + value.createAndAdd.map(async input => { const parseFields = await transformTypes('create', input, { className: targetClass, - originalFields: originalValue.createAndAdd[i], parseGraphQLSchema, req: { config, auth, info }, }); @@ -216,14 +204,7 @@ const transformers = { } return op; }, - pointer: async ( - targetClass, - field, - value, - originalValue, - parseGraphQLSchema, - { config, auth, info } - ) => { + pointer: async (targetClass, field, value, parseGraphQLSchema, { config, auth, info }) => { if (Object.keys(value).length > 1 || Object.keys(value).length === 0) throw new Parse.Error( Parse.Error.INVALID_POINTER, @@ -235,7 +216,6 @@ const transformers = { const parseFields = await transformTypes('create', value.createAndLink, { className: targetClass, parseGraphQLSchema, - originalFields: originalValue.createAndLink, req: { config, auth, info }, }); nestedObjectToAdd = await objectsMutations.createObject( diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 004ef46810..d0b535f3a1 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -23,6 +23,7 @@ import { LRUCache as LRU } from 'lru-cache'; 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 { @@ -919,6 +920,13 @@ class ParseLiveQueryServer { ? request.query.keys : request.query.keys.split(','); } + if (request.query.fields) { + subscriptionInfo.keys = request.query.fields; + Deprecator.logRuntimeDeprecation({ + usage: `Subscribing using fields parameter`, + solution: `Subscribe using "keys" instead.`, + }); + } if (request.query.watch) { subscriptionInfo.watch = request.query.watch; } diff --git a/src/LiveQuery/RequestSchema.js b/src/LiveQuery/RequestSchema.js index 6e0a0566b2..3a88e9930d 100644 --- a/src/LiveQuery/RequestSchema.js +++ b/src/LiveQuery/RequestSchema.js @@ -62,6 +62,14 @@ const subscribe = { where: { type: 'object', }, + fields: { + type: 'array', + items: { + type: 'string', + }, + minItems: 1, + uniqueItems: true, + }, keys: { type: 'array', items: { @@ -108,6 +116,14 @@ const update = { where: { type: 'object', }, + fields: { + type: 'array', + items: { + type: 'string', + }, + minItems: 1, + uniqueItems: true, + }, keys: { type: 'array', items: { diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index f4c9619633..3815902c51 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -70,9 +70,9 @@ module.exports.ParseServerOptions = { allowExpiredAuthDataToken: { env: 'PARSE_SERVER_ALLOW_EXPIRED_AUTH_DATA_TOKEN', help: - '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 `false`.', + '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`.', action: parsers.booleanParser, - default: false, + default: true, }, allowHeaders: { env: 'PARSE_SERVER_ALLOW_HEADERS', @@ -103,6 +103,7 @@ module.exports.ParseServerOptions = { env: 'PARSE_SERVER_AUTH_PROVIDERS', help: 'Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication', + action: parsers.arrayParser, }, cacheAdapter: { env: 'PARSE_SERVER_CACHE_ADAPTER', @@ -139,20 +140,6 @@ module.exports.ParseServerOptions = { help: 'A collection prefix for the classes', default: '', }, - convertEmailToLowercase: { - env: 'PARSE_SERVER_CONVERT_EMAIL_TO_LOWERCASE', - help: - 'Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`.', - action: parsers.booleanParser, - default: false, - }, - convertUsernameToLowercase: { - env: 'PARSE_SERVER_CONVERT_USERNAME_TO_LOWERCASE', - help: - 'Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`.', - action: parsers.booleanParser, - default: false, - }, customPages: { env: 'PARSE_SERVER_CUSTOM_PAGES', help: 'custom pages for password validation and reset', @@ -217,26 +204,12 @@ module.exports.ParseServerOptions = { action: parsers.booleanParser, default: true, }, - enableCollationCaseComparison: { - env: 'PARSE_SERVER_ENABLE_COLLATION_CASE_COMPARISON', - help: - 'Optional. If set to `true`, the collation rule of case comparison for queries and indexes is enabled. Enable this option to run Parse Server with MongoDB Atlas Serverless or AWS Amazon DocumentDB. If `false`, the collation rule of case comparison is disabled. Default is `false`.', - action: parsers.booleanParser, - default: false, - }, enableExpressErrorHandler: { env: 'PARSE_SERVER_ENABLE_EXPRESS_ERROR_HANDLER', help: 'Enables the default express error handler for all errors', action: parsers.booleanParser, default: false, }, - encodeParseObjectInCloudFunction: { - env: 'PARSE_SERVER_ENCODE_PARSE_OBJECT_IN_CLOUD_FUNCTION', - help: - 'If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

\u2139\uFE0F The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`.', - action: parsers.booleanParser, - default: false, - }, encryptionKey: { env: 'PARSE_SERVER_ENCRYPTION_KEY', help: 'Key for encrypting your files', @@ -338,13 +311,13 @@ module.exports.ParseServerOptions = { maintenanceKey: { env: 'PARSE_SERVER_MAINTENANCE_KEY', help: - '(Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

\u26A0\uFE0F This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server.', + '(Optional) The maintenance key is used for modifying internal fields of Parse Server.

\u26A0\uFE0F This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server.', required: true, }, maintenanceKeyIps: { env: 'PARSE_SERVER_MAINTENANCE_KEY_IPS', help: - "(Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key.", + "(Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key.", action: parsers.arrayParser, default: ['127.0.0.1', '::1'], }, @@ -356,7 +329,7 @@ module.exports.ParseServerOptions = { masterKeyIps: { env: 'PARSE_SERVER_MASTER_KEY_IPS', help: - "(Optional) Restricts the use of master key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the master key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `\"0.0.0.0/0,::0\"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the master key.", + "(Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key.", action: parsers.arrayParser, default: ['127.0.0.1', '::1'], }, @@ -523,12 +496,6 @@ module.exports.ParseServerOptions = { action: parsers.objectParser, default: {}, }, - sendUserEmailVerification: { - env: 'PARSE_SERVER_SEND_USER_EMAIL_VERIFICATION', - help: - 'Set to `false` to prevent sending of verification email. Supports a function with a return value of `true` or `false` for conditional email sending.

Default is `true`.
', - default: true, - }, serverCloseComplete: { env: 'PARSE_SERVER_SERVER_CLOSE_COMPLETE', help: 'Callback when server has closed', @@ -575,7 +542,8 @@ module.exports.ParseServerOptions = { verifyUserEmails: { env: 'PARSE_SERVER_VERIFY_USER_EMAILS', help: - 'Set to `true` to require users to verify their email address to complete the sign-up process. Supports a function with a return value of `true` or `false` for conditional verification.

Default is `false`.', + 'Set to `true` to require users to verify their email address to complete the sign-up process.

Default is `false`.', + action: parsers.booleanParser, default: false, }, webhookKey: { @@ -1046,7 +1014,7 @@ module.exports.AuthAdapter = { enabled: { help: 'Is `true` if the auth adapter is enabled, `false` otherwise.', action: parsers.booleanParser, - default: false, + default: true, }, }; module.exports.LogLevels = { @@ -1063,19 +1031,19 @@ module.exports.LogLevels = { triggerAfter: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_AFTER', help: - 'Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`.', + 'Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterSaveFile`, `afterDeleteFile`, `afterFind`, `afterLogout`. Default is `info`.', default: 'info', }, triggerBeforeError: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_BEFORE_ERROR', help: - 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`.', + 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on error. Default is `error `.', default: 'error', }, triggerBeforeSuccess: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_BEFORE_SUCCESS', help: - 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`.', + 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on success. Default is `info`.', default: 'info', }, }; diff --git a/src/Options/docs.js b/src/Options/docs.js index 2938662949..847e7df944 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -14,13 +14,13 @@ * @property {AccountLockoutOptions} accountLockout The account lockout policy for failed login attempts. * @property {Boolean} allowClientClassCreation Enable (or disable) client class creation, defaults to true * @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 `false`. + * @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|String[]} allowOrigin Sets origins for Access-Control-Allow-Origin. This can be a string for a single origin or an array of strings for multiple origins. * @property {Adapter} analyticsAdapter Adapter module for the analytics * @property {String} appId Your Parse Application ID * @property {String} appName Sets the app name - * @property {Object} auth Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication + * @property {AuthAdapter[]} auth Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication * @property {Adapter} cacheAdapter Adapter module for the cache * @property {Number} cacheMaxSize Sets the maximum size for the in memory cache, defaults to 10000 * @property {Number} cacheTTL Sets the TTL for the in memory cache (in ms), defaults to 5000 (5 seconds) @@ -28,8 +28,6 @@ * @property {String} cloud Full path to your cloud code main.js * @property {Number|Boolean} cluster Run with cluster, optionally set the number of processes default to os.cpus().length * @property {String} collectionPrefix A collection prefix for the classes - * @property {Boolean} convertEmailToLowercase Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`. - * @property {Boolean} convertUsernameToLowercase Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`. * @property {CustomPagesOptions} customPages custom pages for password validation and reset * @property {Adapter} databaseAdapter Adapter module for the database; any options that are not explicitly described here are passed directly to the database client. * @property {DatabaseOptions} databaseOptions Options to pass to the database client @@ -41,9 +39,7 @@ * @property {Boolean} emailVerifyTokenReuseIfValid Set to `true` if a email verification token should be reused in case another token is requested but there is a token that is still valid, i.e. has not expired. This avoids the often observed issue that a user requests multiple emails and does not know which link contains a valid token because each newly generated token would invalidate the previous token.

Default is `false`.
Requires option `verifyUserEmails: true`. * @property {Number} emailVerifyTokenValidityDuration Set the validity duration of the email verification token in seconds after which the token expires. The token is used in the link that is set in the email. After the token expires, the link becomes invalid and a new link has to be sent. If the option is not set or set to `undefined`, then the token never expires.

For example, to expire the token after 2 hours, set a value of 7200 seconds (= 60 seconds * 60 minutes * 2 hours).

Default is `undefined`.
Requires option `verifyUserEmails: true`. * @property {Boolean} enableAnonymousUsers Enable (or disable) anonymous users, defaults to true - * @property {Boolean} enableCollationCaseComparison Optional. If set to `true`, the collation rule of case comparison for queries and indexes is enabled. Enable this option to run Parse Server with MongoDB Atlas Serverless or AWS Amazon DocumentDB. If `false`, the collation rule of case comparison is disabled. Default is `false`. * @property {Boolean} enableExpressErrorHandler Enables the default express error handler for all errors - * @property {Boolean} encodeParseObjectInCloudFunction If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

ℹ️ The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`. * @property {String} encryptionKey Key for encrypting your files * @property {Boolean} enforcePrivateUsers Set to true if new users should be created without public read and write access. * @property {Boolean} expireInactiveSessions Sets whether we should expire the inactive sessions, defaults to true. If false, all new sessions are created with no expiration date. @@ -63,10 +59,10 @@ * @property {String} logLevel Sets the level for logs * @property {LogLevels} logLevels (Optional) Overrides the log levels used internally by Parse Server to log events. * @property {String} logsFolder Folder for the logs (defaults to './logs'); set to null to disable file based logging - * @property {String} maintenanceKey (Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. - * @property {String[]} maintenanceKeyIps (Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key. + * @property {String} maintenanceKey (Optional) The maintenance key is used for modifying internal fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. + * @property {String[]} maintenanceKeyIps (Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key. * @property {String} masterKey Your Parse Master Key - * @property {String[]} masterKeyIps (Optional) Restricts the use of master key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the master key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the master key. + * @property {String[]} masterKeyIps (Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key. * @property {Number} maxLimit Max value for limit option on queries, defaults to unlimited * @property {Number|String} maxLogFiles Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null) * @property {String} maxUploadSize Max file size for uploads, defaults to 20mb @@ -93,7 +89,6 @@ * @property {Boolean} scheduledPush Configuration for push scheduling, defaults to false. * @property {SchemaOptions} schema Defined schema * @property {SecurityOptions} security The security options to identify and report weak security settings. - * @property {Boolean} sendUserEmailVerification Set to `false` to prevent sending of verification email. Supports a function with a return value of `true` or `false` for conditional email sending.

Default is `true`.
* @property {Function} serverCloseComplete Callback when server has closed * @property {String} serverURL URL to your parse server with http:// or https://. * @property {Number} sessionLength Session duration, in seconds, defaults to 1 year @@ -102,7 +97,7 @@ * @property {Any} trustProxy The trust proxy settings. It is important to understand the exact setup of the reverse proxy, since this setting will trust values provided in the Parse Server API request. See the express trust proxy settings documentation. Defaults to `false`. * @property {String[]} userSensitiveFields Personally identifiable information fields in the user table the should be removed for non-authorized users. Deprecated @see protectedFields * @property {Boolean} verbose Set the logging to verbose - * @property {Boolean} verifyUserEmails Set to `true` to require users to verify their email address to complete the sign-up process. Supports a function with a return value of `true` or `false` for conditional verification.

Default is `false`. + * @property {Boolean} verifyUserEmails Set to `true` to require users to verify their email address to complete the sign-up process.

Default is `false`. * @property {String} webhookKey Key sent with outgoing webhook calls */ @@ -247,7 +242,7 @@ * @interface LogLevels * @property {String} cloudFunctionError Log level used by the Cloud Code Functions on error. Default is `error`. * @property {String} cloudFunctionSuccess Log level used by the Cloud Code Functions on success. Default is `info`. - * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. - * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. - * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. + * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterSaveFile`, `afterDeleteFile`, `afterFind`, `afterLogout`. Default is `info`. + * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on error. Default is `error `. + * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on success. Default is `info`. */ diff --git a/src/Options/index.js b/src/Options/index.js index 22c86d255e..87813147f7 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -47,16 +47,16 @@ export interface ParseServerOptions { appId: string; /* Your Parse Master Key */ masterKey: string; - /* (Optional) The maintenance key is used for modifying internal and read-only fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. */ + /* (Optional) The maintenance key is used for modifying internal fields of Parse Server.

⚠️ This key is not intended to be used as part of a regular operation of Parse Server. This key is intended to conduct out-of-band changes such as one-time migrations or data correction tasks. Internal fields are not officially documented and may change at any time without publication in release changelogs. We strongly advice not to rely on internal fields as part of your regular operation and to investigate the implications of any planned changes *directly in the source code* of your current version of Parse Server. */ maintenanceKey: string; /* URL to your parse server with http:// or https://. :ENV: PARSE_SERVER_URL */ serverURL: string; - /* (Optional) Restricts the use of master key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the master key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the master key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the master key. + /* (Optional) Restricts the use of master key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `masterKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the master key can be used from any IP address.

To connect Parse Dashboard from a different server requires to add the IP address of the server that hosts Parse Dashboard because Parse Dashboard uses the master key.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the master key. :DEFAULT: ["127.0.0.1","::1"] */ masterKeyIps: ?(string[]); - /* (Optional) Restricts the use of maintenance key permissions to a list of IP addresses or ranges.

This option accepts a list of single IP addresses, for example `['10.0.0.1', '10.0.0.2']`. You can also use CIDR notation to specify an IP address range, for example `['10.0.1.0/24']`.

Special scenarios:
- Setting an empty array `[]` means that the maintenance key cannot be used even in Parse Server Cloud Code. This value cannot be set via an environment variable as there is no way to pass an empty array to Parse Server via an environment variable.
- Setting `['0.0.0.0/0', '::0']` means to allow any IPv4 and IPv6 address to use the maintenance key and effectively disables the IP filter.

Considerations:
- IPv4 and IPv6 addresses are not compared against each other. Each IP version (IPv4 and IPv6) needs to be considered separately. For example, `['0.0.0.0/0']` allows any IPv4 address and blocks every IPv6 address. Conversely, `['::0']` allows any IPv6 address and blocks every IPv4 address.
- Keep in mind that the IP version in use depends on the network stack of the environment in which Parse Server runs. A local environment may use a different IP version than a remote environment. For example, it's possible that locally the value `['0.0.0.0/0']` allows the request IP because the environment is using IPv4, but when Parse Server is deployed remotely the request IP is blocked because the remote environment is using IPv6.
- When setting the option via an environment variable the notation is a comma-separated string, for example `"0.0.0.0/0,::0"`.
- IPv6 zone indices (`%` suffix) are not supported, for example `fe80::1%eth0`, `fe80::1%1` or `::1%lo`.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server instance on which Parse Server runs, is allowed to use the maintenance key. - :DEFAULT: ["127.0.0.1","::1"] */ + /* (Optional) Restricts the use of maintenance key permissions to a list of IP addresses.

This option accepts a list of single IP addresses, for example:
`['10.0.0.1', '10.0.0.2']`

You can also use CIDR notation to specify an IP address range, for example:
`['10.0.1.0/24']`

Special cases:
- Setting an empty array `[]` means that `maintenanceKey` cannot be used even in Parse Server Cloud Code.
- Setting `['0.0.0.0/0']` means disabling the filter and the maintenance key can be used from any IP address.

Defaults to `['127.0.0.1', '::1']` which means that only `localhost`, the server itself, is allowed to use the maintenance key. + :DEFAULT: ["127.0.0.1","::1"] */ maintenanceKeyIps: ?(string[]); /* Sets the app name */ appName: ?string; @@ -103,15 +103,6 @@ export interface ParseServerOptions { databaseOptions: ?DatabaseOptions; /* Adapter module for the database; any options that are not explicitly described here are passed directly to the database client. */ databaseAdapter: ?Adapter; - /* Optional. If set to `true`, the collation rule of case comparison for queries and indexes is enabled. Enable this option to run Parse Server with MongoDB Atlas Serverless or AWS Amazon DocumentDB. If `false`, the collation rule of case comparison is disabled. Default is `false`. - :DEFAULT: false */ - enableCollationCaseComparison: ?boolean; - /* Optional. If set to `true`, the `email` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `email` property is stored as set, without any case modifications. Default is `false`. - :DEFAULT: false */ - convertEmailToLowercase: ?boolean; - /* Optional. If set to `true`, the `username` property of a user is automatically converted to lowercase before being stored in the database. Consequently, queries must match the case as stored in the database, which would be lowercase in this scenario. If `false`, the `username` property is stored as set, without any case modifications. Default is `false`. - :DEFAULT: false */ - convertUsernameToLowercase: ?boolean; /* Full path to your cloud code main.js */ cloud: ?string; /* A collection prefix for the classes @@ -158,15 +149,15 @@ export interface ParseServerOptions { allowCustomObjectId: ?boolean; /* Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication :ENV: PARSE_SERVER_AUTH_PROVIDERS */ - auth: ?{ [string]: AuthAdapter }; + auth: ?(AuthAdapter[]); /* Max file size for uploads, defaults to 20mb :DEFAULT: 20mb */ maxUploadSize: ?string; - /* Set to `true` to require users to verify their email address to complete the sign-up process. Supports a function with a return value of `true` or `false` for conditional verification. + /* Set to `true` to require users to verify their email address to complete the sign-up process.

Default is `false`. :DEFAULT: false */ - verifyUserEmails: ?(boolean | void); + verifyUserEmails: ?boolean; /* Set to `true` to prevent a user from logging in if the email has not yet been verified and email verification is required.

Default is `false`. @@ -197,12 +188,6 @@ export interface ParseServerOptions { Requires option `verifyUserEmails: true`. :DEFAULT: false */ emailVerifyTokenReuseIfValid: ?boolean; - /* Set to `false` to prevent sending of verification email. Supports a function with a return value of `true` or `false` for conditional email sending. -

- Default is `true`. -
- :DEFAULT: true */ - sendUserEmailVerification: ?(boolean | void); /* The account lockout policy for failed login attempts. */ accountLockout: ?AccountLockoutOptions; /* The password policy for enforcing password related rules. */ @@ -211,9 +196,6 @@ export interface ParseServerOptions { cacheAdapter: ?Adapter; /* Adapter module for email sending */ emailAdapter: ?Adapter; - /* If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

ℹ️ The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`. - :DEFAULT: false */ - encodeParseObjectInCloudFunction: ?boolean; /* Public URL to your parse server with http:// or https://. :ENV: PARSE_PUBLIC_SERVER_URL */ publicServerURL: ?string; @@ -320,8 +302,8 @@ export interface ParseServerOptions { /* Set to true if new users should be created without public read and write access. :DEFAULT: true */ enforcePrivateUsers: ?boolean; - /* 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 `false`. - :DEFAULT: false */ + /* 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`. + :DEFAULT: true */ allowExpiredAuthDataToken: ?boolean; /* An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns. :DEFAULT: [{"key":"_bsontype","value":"Code"},{"key":"constructor"},{"key":"__proto__"}] */ @@ -600,22 +582,22 @@ export interface DatabaseOptions { export interface AuthAdapter { /* Is `true` if the auth adapter is enabled, `false` otherwise. - :DEFAULT: false + :DEFAULT: true :ENV: */ enabled: ?boolean; } export interface LogLevels { - /* Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. + /* Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterSaveFile`, `afterDeleteFile`, `afterFind`, `afterLogout`. Default is `info`. :DEFAULT: info */ triggerAfter: ?string; - /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. + /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on success. Default is `info`. :DEFAULT: info */ triggerBeforeSuccess: ?string; - /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. + /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on error. Default is `error `. :DEFAULT: error */ triggerBeforeError: ?string; diff --git a/src/ParseServer.js b/src/ParseServer.js index 880c5f84aa..6465e1f3c9 100644 --- a/src/ParseServer.js +++ b/src/ParseServer.js @@ -75,8 +75,6 @@ class ParseServer { const allControllers = controllers.getControllers(options); options.state = 'initialized'; this.config = Config.put(Object.assign({}, options, allControllers)); - this.config.masterKeyIpsStore = new Map(); - this.config.maintenanceKeyIpsStore = new Map(); logging.setLogger(allControllers.loggerController); } @@ -244,15 +242,7 @@ class ParseServer { process.stderr.write(`Unable to listen on port ${err.port}. The port is already in use.`); process.exit(0); } else { - if (err.message) { - process.stderr.write('An uncaught exception occurred: ' + err.message); - } - if (err.stack) { - process.stderr.write('Stack Trace:\n' + err.stack); - } else { - process.stderr.write(err); - } - process.exit(1); + throw err; } }); // verify the server url after a 'mount' event is received diff --git a/src/RestQuery.js b/src/RestQuery.js index 5af678bb96..fe3617eb1b 100644 --- a/src/RestQuery.js +++ b/src/RestQuery.js @@ -6,8 +6,6 @@ var Parse = require('parse/node').Parse; const triggers = require('./triggers'); const { continueWhile } = require('parse/lib/node/promiseUtils'); const AlwaysSelectedKeys = ['objectId', 'createdAt', 'updatedAt', 'ACL']; -const { enforceRoleSecurity } = require('./SharedRest'); - // restOptions can include: // skip // limit @@ -20,80 +18,7 @@ const { enforceRoleSecurity } = require('./SharedRest'); // readPreference // includeReadPreference // subqueryReadPreference -/** - * Use to perform a query on a class. It will run security checks and triggers. - * @param options - * @param options.method {RestQuery.Method} The type of query to perform - * @param options.config {ParseServerConfiguration} The server configuration - * @param options.auth {Auth} The auth object for the request - * @param options.className {string} The name of the class to query - * @param options.restWhere {object} The where object for the query - * @param options.restOptions {object} The options object for the query - * @param options.clientSDK {string} The client SDK that is performing the query - * @param options.runAfterFind {boolean} Whether to run the afterFind trigger - * @param options.runBeforeFind {boolean} Whether to run the beforeFind trigger - * @param options.context {object} The context object for the query - * @returns {Promise<_UnsafeRestQuery>} A promise that is resolved with the _UnsafeRestQuery object - */ -async function RestQuery({ - method, - config, - auth, - className, - restWhere = {}, - restOptions = {}, - clientSDK, - runAfterFind = true, - runBeforeFind = true, - context, -}) { - if (![RestQuery.Method.find, RestQuery.Method.get].includes(method)) { - throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad query type'); - } - enforceRoleSecurity(method, className, auth); - const result = runBeforeFind - ? await triggers.maybeRunQueryTrigger( - triggers.Types.beforeFind, - className, - restWhere, - restOptions, - config, - auth, - context, - method === RestQuery.Method.get - ) - : Promise.resolve({ restWhere, restOptions }); - - return new _UnsafeRestQuery( - config, - auth, - className, - result.restWhere || restWhere, - result.restOptions || restOptions, - clientSDK, - runAfterFind, - context - ); -} - -RestQuery.Method = Object.freeze({ - get: 'get', - find: 'find', -}); - -/** - * _UnsafeRestQuery is meant for specific internal usage only. When you need to skip security checks or some triggers. - * Don't use it if you don't know what you are doing. - * @param config - * @param auth - * @param className - * @param restWhere - * @param restOptions - * @param clientSDK - * @param runAfterFind - * @param context - */ -function _UnsafeRestQuery( +function RestQuery( config, auth, className, @@ -272,7 +197,7 @@ function _UnsafeRestQuery( // Returns a promise for the response - an object with optional keys // 'results' and 'count'. // TODO: consolidate the replaceX functions -_UnsafeRestQuery.prototype.execute = function (executeOptions) { +RestQuery.prototype.execute = function (executeOptions) { return Promise.resolve() .then(() => { return this.buildRestWhere(); @@ -306,7 +231,7 @@ _UnsafeRestQuery.prototype.execute = function (executeOptions) { }); }; -_UnsafeRestQuery.prototype.each = function (callback) { +RestQuery.prototype.each = function (callback) { const { config, auth, className, restWhere, restOptions, clientSDK } = this; // if the limit is set, use it restOptions.limit = restOptions.limit || 100; @@ -318,9 +243,7 @@ _UnsafeRestQuery.prototype.each = function (callback) { return !finished; }, async () => { - // Safe here to use _UnsafeRestQuery because the security was already - // checked during "await RestQuery()" - const query = new _UnsafeRestQuery( + const query = new RestQuery( config, auth, className, @@ -342,7 +265,7 @@ _UnsafeRestQuery.prototype.each = function (callback) { ); }; -_UnsafeRestQuery.prototype.buildRestWhere = function () { +RestQuery.prototype.buildRestWhere = function () { return Promise.resolve() .then(() => { return this.getUserAndRoleACL(); @@ -371,7 +294,7 @@ _UnsafeRestQuery.prototype.buildRestWhere = function () { }; // Uses the Auth object to get the list of roles, adds the user id -_UnsafeRestQuery.prototype.getUserAndRoleACL = function () { +RestQuery.prototype.getUserAndRoleACL = function () { if (this.auth.isMaster) { return Promise.resolve(); } @@ -390,7 +313,7 @@ _UnsafeRestQuery.prototype.getUserAndRoleACL = function () { // Changes the className if redirectClassNameForKey is set. // Returns a promise. -_UnsafeRestQuery.prototype.redirectClassNameForKey = function () { +RestQuery.prototype.redirectClassNameForKey = function () { if (!this.redirectKey) { return Promise.resolve(); } @@ -405,7 +328,7 @@ _UnsafeRestQuery.prototype.redirectClassNameForKey = function () { }; // Validates this operation against the allowClientClassCreation config. -_UnsafeRestQuery.prototype.validateClientClassCreation = function () { +RestQuery.prototype.validateClientClassCreation = function () { if ( this.config.allowClientClassCreation === false && !this.auth.isMaster && @@ -448,7 +371,7 @@ function transformInQuery(inQueryObject, className, results) { // $inQuery clause. // The $inQuery clause turns into an $in with values that are just // pointers to the objects returned in the subquery. -_UnsafeRestQuery.prototype.replaceInQuery = async function () { +RestQuery.prototype.replaceInQuery = function () { var inQueryObject = findObjectWithKey(this.restWhere, '$inQuery'); if (!inQueryObject) { return; @@ -471,15 +394,13 @@ _UnsafeRestQuery.prototype.replaceInQuery = async function () { additionalOptions.readPreference = this.restOptions.readPreference; } - const subquery = await RestQuery({ - method: RestQuery.Method.find, - config: this.config, - auth: this.auth, - className: inQueryValue.className, - restWhere: inQueryValue.where, - restOptions: additionalOptions, - context: this.context, - }); + var subquery = new RestQuery( + this.config, + this.auth, + inQueryValue.className, + inQueryValue.where, + additionalOptions + ); return subquery.execute().then(response => { transformInQuery(inQueryObject, subquery.className, response.results); // Recurse to repeat @@ -508,7 +429,7 @@ function transformNotInQuery(notInQueryObject, className, results) { // $notInQuery clause. // The $notInQuery clause turns into a $nin with values that are just // pointers to the objects returned in the subquery. -_UnsafeRestQuery.prototype.replaceNotInQuery = async function () { +RestQuery.prototype.replaceNotInQuery = function () { var notInQueryObject = findObjectWithKey(this.restWhere, '$notInQuery'); if (!notInQueryObject) { return; @@ -531,16 +452,13 @@ _UnsafeRestQuery.prototype.replaceNotInQuery = async function () { additionalOptions.readPreference = this.restOptions.readPreference; } - const subquery = await RestQuery({ - method: RestQuery.Method.find, - config: this.config, - auth: this.auth, - className: notInQueryValue.className, - restWhere: notInQueryValue.where, - restOptions: additionalOptions, - context: this.context, - }); - + var subquery = new RestQuery( + this.config, + this.auth, + notInQueryValue.className, + notInQueryValue.where, + additionalOptions + ); return subquery.execute().then(response => { transformNotInQuery(notInQueryObject, subquery.className, response.results); // Recurse to repeat @@ -574,7 +492,7 @@ const transformSelect = (selectObject, key, objects) => { // The $select clause turns into an $in with values selected out of // the subquery. // Returns a possible-promise. -_UnsafeRestQuery.prototype.replaceSelect = async function () { +RestQuery.prototype.replaceSelect = function () { var selectObject = findObjectWithKey(this.restWhere, '$select'); if (!selectObject) { return; @@ -604,16 +522,13 @@ _UnsafeRestQuery.prototype.replaceSelect = async function () { additionalOptions.readPreference = this.restOptions.readPreference; } - const subquery = await RestQuery({ - method: RestQuery.Method.find, - config: this.config, - auth: this.auth, - className: selectValue.query.className, - restWhere: selectValue.query.where, - restOptions: additionalOptions, - context: this.context, - }); - + var subquery = new RestQuery( + this.config, + this.auth, + selectValue.query.className, + selectValue.query.where, + additionalOptions + ); return subquery.execute().then(response => { transformSelect(selectObject, selectValue.key, response.results); // Keep replacing $select clauses @@ -639,7 +554,7 @@ const transformDontSelect = (dontSelectObject, key, objects) => { // The $dontSelect clause turns into an $nin with values selected out of // the subquery. // Returns a possible-promise. -_UnsafeRestQuery.prototype.replaceDontSelect = async function () { +RestQuery.prototype.replaceDontSelect = function () { var dontSelectObject = findObjectWithKey(this.restWhere, '$dontSelect'); if (!dontSelectObject) { return; @@ -667,16 +582,13 @@ _UnsafeRestQuery.prototype.replaceDontSelect = async function () { additionalOptions.readPreference = this.restOptions.readPreference; } - const subquery = await RestQuery({ - method: RestQuery.Method.find, - config: this.config, - auth: this.auth, - className: dontSelectValue.query.className, - restWhere: dontSelectValue.query.where, - restOptions: additionalOptions, - context: this.context, - }); - + var subquery = new RestQuery( + this.config, + this.auth, + dontSelectValue.query.className, + dontSelectValue.query.where, + additionalOptions + ); return subquery.execute().then(response => { transformDontSelect(dontSelectObject, dontSelectValue.key, response.results); // Keep replacing $dontSelect clauses @@ -684,7 +596,7 @@ _UnsafeRestQuery.prototype.replaceDontSelect = async function () { }); }; -_UnsafeRestQuery.prototype.cleanResultAuthData = function (result) { +RestQuery.prototype.cleanResultAuthData = function (result) { delete result.password; if (result.authData) { Object.keys(result.authData).forEach(provider => { @@ -723,7 +635,7 @@ const replaceEqualityConstraint = constraint => { return constraint; }; -_UnsafeRestQuery.prototype.replaceEquality = function () { +RestQuery.prototype.replaceEquality = function () { if (typeof this.restWhere !== 'object') { return; } @@ -734,7 +646,7 @@ _UnsafeRestQuery.prototype.replaceEquality = function () { // Returns a promise for whether it was successful. // Populates this.response with an object that only has 'results'. -_UnsafeRestQuery.prototype.runFind = function (options = {}) { +RestQuery.prototype.runFind = function (options = {}) { if (this.findOptions.limit === 0) { this.response = { results: [] }; return Promise.resolve(); @@ -770,7 +682,7 @@ _UnsafeRestQuery.prototype.runFind = function (options = {}) { // Returns a promise for whether it was successful. // Populates this.response.count with the count -_UnsafeRestQuery.prototype.runCount = function () { +RestQuery.prototype.runCount = function () { if (!this.doCount) { return; } @@ -782,7 +694,7 @@ _UnsafeRestQuery.prototype.runCount = function () { }); }; -_UnsafeRestQuery.prototype.denyProtectedFields = async function () { +RestQuery.prototype.denyProtectedFields = async function () { if (this.auth.isMaster) { return; } @@ -807,7 +719,7 @@ _UnsafeRestQuery.prototype.denyProtectedFields = async function () { }; // Augments this.response with all pointers on an object -_UnsafeRestQuery.prototype.handleIncludeAll = function () { +RestQuery.prototype.handleIncludeAll = function () { if (!this.includeAll) { return; } @@ -836,7 +748,7 @@ _UnsafeRestQuery.prototype.handleIncludeAll = function () { }; // Updates property `this.keys` to contain all keys but the ones unselected. -_UnsafeRestQuery.prototype.handleExcludeKeys = function () { +RestQuery.prototype.handleExcludeKeys = function () { if (!this.excludeKeys) { return; } @@ -854,7 +766,7 @@ _UnsafeRestQuery.prototype.handleExcludeKeys = function () { }; // Augments this.response with data at the paths provided in this.include. -_UnsafeRestQuery.prototype.handleInclude = function () { +RestQuery.prototype.handleInclude = function () { if (this.include.length == 0) { return; } @@ -864,7 +776,6 @@ _UnsafeRestQuery.prototype.handleInclude = function () { this.auth, this.response, this.include[0], - this.context, this.restOptions ); if (pathResponse.then) { @@ -882,7 +793,7 @@ _UnsafeRestQuery.prototype.handleInclude = function () { }; //Returns a promise of a processed set of results -_UnsafeRestQuery.prototype.runAfterFindTrigger = function () { +RestQuery.prototype.runAfterFindTrigger = function () { if (!this.response) { return; } @@ -934,7 +845,7 @@ _UnsafeRestQuery.prototype.runAfterFindTrigger = function () { }); }; -_UnsafeRestQuery.prototype.handleAuthAdapters = async function () { +RestQuery.prototype.handleAuthAdapters = async function () { if (this.className !== '_User' || this.findOptions.explain) { return; } @@ -951,7 +862,7 @@ _UnsafeRestQuery.prototype.handleAuthAdapters = async function () { // Adds included values to the response. // Path is a list of field names. // Returns a promise for an augmented response. -function includePath(config, auth, response, path, context, restOptions = {}) { +function includePath(config, auth, response, path, restOptions = {}) { var pointers = findPointers(response.results, path); if (pointers.length == 0) { return response; @@ -1016,7 +927,7 @@ function includePath(config, auth, response, path, context, restOptions = {}) { includeRestOptions.readPreference = restOptions.readPreference; } - const queryPromises = Object.keys(pointersHash).map(async className => { + const queryPromises = Object.keys(pointersHash).map(className => { const objectIds = Array.from(pointersHash[className]); let where; if (objectIds.length === 1) { @@ -1024,15 +935,7 @@ function includePath(config, auth, response, path, context, restOptions = {}) { } else { where = { objectId: { $in: objectIds } }; } - const query = await RestQuery({ - method: objectIds.length === 1 ? RestQuery.Method.get : RestQuery.Method.find, - config, - auth, - className, - restWhere: where, - restOptions: includeRestOptions, - context: context, - }); + var query = new RestQuery(config, auth, className, where, includeRestOptions); return query.execute({ op: 'get' }).then(results => { results.className = className; return Promise.resolve(results); @@ -1072,7 +975,11 @@ function includePath(config, auth, response, path, context, restOptions = {}) { // Returns a list of pointers in REST format. function findPointers(object, path) { if (object instanceof Array) { - return object.map(x => findPointers(x, path)).flat(); + var answer = []; + for (var x of object) { + answer = answer.concat(findPointers(x, path)); + } + return answer; } if (typeof object !== 'object' || !object) { @@ -1159,5 +1066,3 @@ function findObjectWithKey(root, key) { } module.exports = RestQuery; -// For tests -module.exports._UnsafeRestQuery = _UnsafeRestQuery; diff --git a/src/RestWrite.js b/src/RestWrite.js index 7243238cfa..f7c6a53592 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -64,6 +64,8 @@ function RestWrite(config, auth, className, query, data, originalData, clientSDK } } + this.checkProhibitedKeywords(data); + // When the operation is complete, this.response may have several // fields. // response: the actual data to be returned @@ -111,9 +113,6 @@ RestWrite.prototype.execute = function () { .then(() => { return this.validateAuthData(); }) - .then(() => { - return this.checkRestrictedFields(); - }) .then(() => { return this.runBeforeSaveTrigger(); }) @@ -302,11 +301,7 @@ RestWrite.prototype.runBeforeSaveTrigger = function () { delete this.data.objectId; } } - try { - Utils.checkProhibitedKeywords(this.config, this.data); - } catch (error) { - throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, error); - } + this.checkProhibitedKeywords(this.data); }); }; @@ -368,36 +363,9 @@ RestWrite.prototype.setRequiredFieldsIfNeeded = function () { }; // Add default fields + this.data.updatedAt = this.updatedAt; if (!this.query) { - // allow customizing createdAt and updatedAt when using maintenance key - if ( - this.auth.isMaintenance && - this.data.createdAt && - this.data.createdAt.__type === 'Date' - ) { - this.data.createdAt = this.data.createdAt.iso; - - if (this.data.updatedAt && this.data.updatedAt.__type === 'Date') { - const createdAt = new Date(this.data.createdAt); - const updatedAt = new Date(this.data.updatedAt.iso); - - if (updatedAt < createdAt) { - throw new Parse.Error( - Parse.Error.VALIDATION_ERROR, - 'updatedAt cannot occur before createdAt' - ); - } - - this.data.updatedAt = this.data.updatedAt.iso; - } - // if no updatedAt is provided, set it to createdAt to match default behavior - else { - this.data.updatedAt = this.data.createdAt; - } - } else { - this.data.updatedAt = this.updatedAt; - this.data.createdAt = this.updatedAt; - } + this.data.createdAt = this.updatedAt; // Only assign new objectId if we are creating new object if (!this.data.objectId) { @@ -409,8 +377,6 @@ RestWrite.prototype.setRequiredFieldsIfNeeded = function () { }); } } else if (schema) { - this.data.updatedAt = this.updatedAt; - Object.keys(this.data).forEach(fieldName => { setRequiredFieldIfNeeded(fieldName, false); }); @@ -587,7 +553,6 @@ RestWrite.prototype.handleAuthData = async function (authData) { // we need to be sure that the user has provided // required authData Auth.checkIfUserHasProvidedConfiguredProvidersForLogin( - { config: this.config, auth: this.auth }, authData, userResult.authData, this.config @@ -638,47 +603,35 @@ RestWrite.prototype.handleAuthData = async function (authData) { } }; -RestWrite.prototype.checkRestrictedFields = async function () { +// The non-third-party parts of User transformation +RestWrite.prototype.transformUser = function () { + var promise = Promise.resolve(); if (this.className !== '_User') { - return; + return promise; } if (!this.auth.isMaintenance && !this.auth.isMaster && 'emailVerified' in this.data) { const error = `Clients aren't allowed to manually update email verification.`; throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); } -}; - -// The non-third-party parts of User transformation -RestWrite.prototype.transformUser = async function () { - var promise = Promise.resolve(); - if (this.className !== '_User') { - return promise; - } // Do not cleanup session if objectId is not set if (this.query && this.objectId()) { // If we're updating a _User object, we need to clear out the cache for that user. Find all their // session tokens, and remove them from the cache. - const query = await RestQuery({ - method: RestQuery.Method.find, - config: this.config, - auth: Auth.master(this.config), - className: '_Session', - runBeforeFind: false, - restWhere: { - user: { - __type: 'Pointer', - className: '_User', - objectId: this.objectId(), - }, + promise = new RestQuery(this.config, Auth.master(this.config), '_Session', { + user: { + __type: 'Pointer', + className: '_User', + objectId: this.objectId(), }, - }); - promise = query.execute().then(results => { - results.results.forEach(session => - this.config.cacheController.user.del(session.sessionToken) - ); - }); + }) + .execute() + .then(results => { + results.results.forEach(session => + this.config.cacheController.user.del(session.sessionToken) + ); + }); } return promise @@ -798,15 +751,8 @@ RestWrite.prototype._validateEmail = function () { Object.keys(this.data.authData)[0] === 'anonymous') ) { // We updated the email, send a new validation - const { originalObject, updatedObject } = this.buildParseObjects(); - const request = { - original: originalObject, - object: updatedObject, - master: this.auth.isMaster, - ip: this.config.ip, - installationId: this.auth.installationId, - }; - return this.config.userController.setEmailVerifyToken(this.data, request, this.storage); + this.storage['sendVerificationEmail'] = true; + this.config.userController.setEmailVerifyToken(this.data); } }); }; @@ -918,7 +864,7 @@ RestWrite.prototype._validatePasswordHistory = function () { return Promise.resolve(); }; -RestWrite.prototype.createSessionTokenIfNeeded = async function () { +RestWrite.prototype.createSessionTokenIfNeeded = function () { if (this.className !== '_User') { return; } @@ -930,27 +876,14 @@ RestWrite.prototype.createSessionTokenIfNeeded = async function () { if (this.auth.user && this.data.authData) { return; } - // If sign-up call - if (!this.storage.authProvider) { - // Create request object for verification functions - const { originalObject, updatedObject } = this.buildParseObjects(); - const request = { - original: originalObject, - object: updatedObject, - master: this.auth.isMaster, - ip: this.config.ip, - installationId: this.auth.installationId, - }; - // Get verification conditions which can be booleans or functions; the purpose of this async/await - // structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the - // conditional statement below, as a developer may decide to execute expensive operations in them - const verifyUserEmails = async () => this.config.verifyUserEmails === true || (typeof this.config.verifyUserEmails === 'function' && await Promise.resolve(this.config.verifyUserEmails(request)) === true); - const preventLoginWithUnverifiedEmail = async () => this.config.preventLoginWithUnverifiedEmail === true || (typeof this.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(this.config.preventLoginWithUnverifiedEmail(request)) === true); - // If verification is required - if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail()) { - this.storage.rejectSignup = true; - return; - } + if ( + !this.storage.authProvider && // signup call, with + this.config.preventLoginWithUnverifiedEmail && // no login without verification + this.config.verifyUserEmails + ) { + // verification is on + this.storage.rejectSignup = true; + return; } return this.createSessionToken(); }; @@ -1077,7 +1010,7 @@ RestWrite.prototype.handleFollowup = function () { if (this.storage && this.storage['sendVerificationEmail']) { delete this.storage['sendVerificationEmail']; // Fire and forget! - this.config.userController.sendVerificationEmail(this.data, { auth: this.auth }); + this.config.userController.sendVerificationEmail(this.data); return this.handleFollowup.bind(this); } }; @@ -1831,5 +1764,20 @@ RestWrite.prototype._updateResponseWithData = function (response, data) { return response; }; +RestWrite.prototype.checkProhibitedKeywords = function (data) { + if (this.config.requestKeywordDenylist) { + // Scan request data for denied keywords + for (const keyword of this.config.requestKeywordDenylist) { + const match = Utils.objectContainsKeyValue(data, keyword.key, keyword.value); + if (match) { + throw new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ); + } + } + } +}; + export default RestWrite; module.exports = RestWrite; diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index 332cd75748..ed48a28a68 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -147,7 +147,7 @@ export class FilesRouter { if (ext === '*') { return true; } - const regex = new RegExp(ext); + const regex = new RegExp(fileExtensions); if (regex.test(extension)) { return true; } @@ -155,13 +155,13 @@ export class FilesRouter { }; let extension = contentType; if (filename && filename.includes('.')) { - extension = filename.substring(filename.lastIndexOf('.') + 1); + extension = filename.split('.')[1]; } else if (contentType && contentType.includes('/')) { extension = contentType.split('/')[1]; } - extension = extension?.split(' ')?.join(''); + extension = extension.split(' ').join(''); - if (extension && !isValidExtension(extension)) { + if (!isValidExtension(extension)) { next( new Parse.Error( Parse.Error.FILE_SAVE_ERROR, @@ -175,13 +175,22 @@ export class FilesRouter { const base64 = req.body.toString('base64'); const file = new Parse.File(filename, { base64 }, contentType); const { metadata = {}, tags = {} } = req.fileData || {}; - try { + if (req.config && req.config.requestKeywordDenylist) { // Scan request data for denied keywords - Utils.checkProhibitedKeywords(config, metadata); - Utils.checkProhibitedKeywords(config, tags); - } catch (error) { - next(new Parse.Error(Parse.Error.INVALID_KEY_NAME, error)); - return; + for (const keyword of req.config.requestKeywordDenylist) { + const match = + Utils.objectContainsKeyValue(metadata, keyword.key, keyword.value) || + Utils.objectContainsKeyValue(tags, keyword.key, keyword.value); + if (match) { + next( + new Parse.Error( + Parse.Error.INVALID_KEY_NAME, + `Prohibited keyword in request data: ${JSON.stringify(keyword)}.` + ) + ); + return; + } + } } file.setTags(tags); file.setMetadata(metadata); diff --git a/src/Routers/FunctionsRouter.js b/src/Routers/FunctionsRouter.js index eab76eeb1b..da69d54e0c 100644 --- a/src/Routers/FunctionsRouter.js +++ b/src/Routers/FunctionsRouter.js @@ -9,30 +9,30 @@ import { jobStatusHandler } from '../StatusHandler'; import _ from 'lodash'; import { logger } from '../logger'; -function parseObject(obj, config) { +function parseObject(obj) { if (Array.isArray(obj)) { return obj.map(item => { - return parseObject(item, config); + return parseObject(item); }); } else if (obj && obj.__type == 'Date') { return Object.assign(new Date(obj.iso), obj); } else if (obj && obj.__type == 'File') { return Parse.File.fromJSON(obj); - } else if (obj && obj.__type == 'Pointer' && config.encodeParseObjectInCloudFunction) { + } else if (obj && obj.__type == 'Pointer') { return Parse.Object.fromJSON({ __type: 'Pointer', className: obj.className, objectId: obj.objectId, }); } else if (obj && typeof obj === 'object') { - return parseParams(obj, config); + return parseParams(obj); } else { return obj; } } -function parseParams(params, config) { - return _.mapValues(params, item => parseObject(item, config)); +function parseParams(params) { + return _.mapValues(params, parseObject); } export class FunctionsRouter extends PromiseRouter { @@ -66,7 +66,7 @@ export class FunctionsRouter extends PromiseRouter { throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'Invalid job.'); } let params = Object.assign({}, req.body, req.query); - params = parseParams(params, req.config); + params = parseParams(params); const request = { params: params, log: req.config.loggerController, @@ -126,7 +126,7 @@ export class FunctionsRouter extends PromiseRouter { throw new Parse.Error(Parse.Error.SCRIPT_FAILED, `Invalid function: "${functionName}"`); } let params = Object.assign({}, req.body, req.query); - params = parseParams(params, req.config); + params = parseParams(params); const request = { params: params, master: req.auth && req.auth.isMaster, diff --git a/src/Routers/PagesRouter.js b/src/Routers/PagesRouter.js index 79a487b6e4..5d5a1467a7 100644 --- a/src/Routers/PagesRouter.js +++ b/src/Routers/PagesRouter.js @@ -125,7 +125,7 @@ export class PagesRouter extends PromiseRouter { const userController = config.userController; - return userController.resendVerificationEmail(username, req).then( + return userController.resendVerificationEmail(username).then( () => { return this.goToPage(req, pages.emailVerificationSendSuccess); }, diff --git a/src/Routers/PublicAPIRouter.js b/src/Routers/PublicAPIRouter.js index ddef76a5b8..5009ee7d22 100644 --- a/src/Routers/PublicAPIRouter.js +++ b/src/Routers/PublicAPIRouter.js @@ -63,7 +63,7 @@ export class PublicAPIRouter extends PromiseRouter { const userController = config.userController; - return userController.resendVerificationEmail(username, req).then( + return userController.resendVerificationEmail(username).then( () => { return Promise.resolve({ status: 302, diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index 8af8dc5434..feca46e802 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -75,7 +75,7 @@ export class UsersRouter extends ClassesRouter { ) { payload = req.query; } - const { username, email, password, ignoreEmailVerification } = payload; + const { username, email, password } = payload; // TODO: use the right error codes / descriptions. if (!username && !email) { @@ -126,7 +126,7 @@ export class UsersRouter extends ClassesRouter { const accountLockoutPolicy = new AccountLockout(user, req.config); return accountLockoutPolicy.handleLoginAttempt(isValidPassword); }) - .then(async () => { + .then(() => { if (!isValidPassword) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.'); } @@ -137,25 +137,12 @@ export class UsersRouter extends ClassesRouter { if (!req.auth.isMaster && user.ACL && Object.keys(user.ACL).length == 0) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.'); } - // Create request object for verification functions - const request = { - master: req.auth.isMaster, - ip: req.config.ip, - installationId: req.auth.installationId, - object: Parse.User.fromJSON(Object.assign({ className: '_User' }, user)), - }; - - // If request doesn't use master or maintenance key with ignoring email verification - if (!((req.auth.isMaster || req.auth.isMaintenance) && ignoreEmailVerification)) { - - // Get verification conditions which can be booleans or functions; the purpose of this async/await - // structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the - // conditional statement below, as a developer may decide to execute expensive operations in them - const verifyUserEmails = async () => req.config.verifyUserEmails === true || (typeof req.config.verifyUserEmails === 'function' && await Promise.resolve(req.config.verifyUserEmails(request)) === true); - const preventLoginWithUnverifiedEmail = async () => req.config.preventLoginWithUnverifiedEmail === true || (typeof req.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(req.config.preventLoginWithUnverifiedEmail(request)) === true); - if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail() && !user.emailVerified) { - throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.'); - } + if ( + req.config.verifyUserEmails && + req.config.preventLoginWithUnverifiedEmail && + !user.emailVerified + ) { + throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.'); } this._sanitizeAuthData(user); @@ -202,12 +189,7 @@ export class UsersRouter extends ClassesRouter { const user = await this._authenticateUserFromRequest(req); const authData = req.body && req.body.authData; // Check if user has provided their required auth providers - Auth.checkIfUserHasProvidedConfiguredProvidersForLogin( - req, - authData, - user.authData, - req.config - ); + Auth.checkIfUserHasProvidedConfiguredProvidersForLogin(authData, user.authData, req.config); let authDataResponse; let validatedAuthData; @@ -272,8 +254,7 @@ export class UsersRouter extends ClassesRouter { req.auth, Parse.User.fromJSON(Object.assign({ className: '_User' }, user)), null, - req.config, - req.info.context + req.config ); // If we have some new validated authData update directly @@ -305,8 +286,7 @@ export class UsersRouter extends ClassesRouter { { ...req.auth, user: afterLoginUser }, afterLoginUser, null, - req.config, - req.info.context + req.config ); if (authDataResponse) { @@ -467,7 +447,7 @@ export class UsersRouter extends ClassesRouter { } } - async handleVerificationEmailRequest(req) { + handleVerificationEmailRequest(req) { this._throwOnBadEmailConfig(req); const { email } = req.body; @@ -481,25 +461,25 @@ export class UsersRouter extends ClassesRouter { ); } - const results = await req.config.database.find('_User', { email: email }, {}, Auth.maintenance(req.config)); - if (!results.length || results.length < 1) { - throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, `No user found with email ${email}`); - } - const user = results[0]; + return req.config.database.find('_User', { email: email }).then(results => { + if (!results.length || results.length < 1) { + throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, `No user found with email ${email}`); + } + const user = results[0]; - // remove password field, messes with saving on postgres - delete user.password; + // remove password field, messes with saving on postgres + delete user.password; - if (user.emailVerified) { - throw new Parse.Error(Parse.Error.OTHER_CAUSE, `Email ${email} is already verified.`); - } + if (user.emailVerified) { + throw new Parse.Error(Parse.Error.OTHER_CAUSE, `Email ${email} is already verified.`); + } - const userController = req.config.userController; - const send = await userController.regenerateEmailVerifyToken(user, req.auth.isMaster, req.auth.installationId, req.ip); - if (send) { - userController.sendVerificationEmail(user, req); - } - return { response: {} }; + const userController = req.config.userController; + return userController.regenerateEmailVerifyToken(user).then(() => { + userController.sendVerificationEmail(user); + return { response: {} }; + }); + }); } async handleChallenge(req) { @@ -663,9 +643,6 @@ export class UsersRouter extends ClassesRouter { this.route('GET', '/verifyPassword', req => { return this.handleVerifyPassword(req); }); - this.route('POST', '/verifyPassword', req => { - return this.handleVerifyPassword(req); - }); this.route('POST', '/challenge', req => { return this.handleChallenge(req); }); diff --git a/src/SharedRest.js b/src/SharedRest.js deleted file mode 100644 index 0b4a07c320..0000000000 --- a/src/SharedRest.js +++ /dev/null @@ -1,37 +0,0 @@ -const classesWithMasterOnlyAccess = [ - '_JobStatus', - '_PushStatus', - '_Hooks', - '_GlobalConfig', - '_JobSchedule', - '_Idempotency', -]; -// Disallowing access to the _Role collection except by master key -function enforceRoleSecurity(method, className, auth) { - if (className === '_Installation' && !auth.isMaster && !auth.isMaintenance) { - if (method === 'delete' || method === 'find') { - const error = `Clients aren't allowed to perform the ${method} operation on the installation collection.`; - throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); - } - } - - //all volatileClasses are masterKey only - if ( - classesWithMasterOnlyAccess.indexOf(className) >= 0 && - !auth.isMaster && - !auth.isMaintenance - ) { - const error = `Clients aren't allowed to perform the ${method} operation on the ${className} collection.`; - throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); - } - - // readOnly masterKey is not allowed - if (auth.isReadOnly && (method === 'delete' || method === 'create' || method === 'update')) { - const error = `read-only masterKey isn't allowed to perform the ${method} operation.`; - throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); - } -} - -module.exports = { - enforceRoleSecurity, -}; diff --git a/src/Utils.js b/src/Utils.js index efeae58f3f..d5a255a5ca 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -358,18 +358,6 @@ class Utils { } return false; } - - static checkProhibitedKeywords(config, data) { - if (config?.requestKeywordDenylist) { - // Scan request data for denied keywords - for (const keyword of config.requestKeywordDenylist) { - const match = Utils.objectContainsKeyValue(data, keyword.key, keyword.value); - if (match) { - throw `Prohibited keyword in request data: ${JSON.stringify(keyword)}.`; - } - } - } - } } module.exports = Utils; diff --git a/src/cli/utils/runner.js b/src/cli/utils/runner.js index 4869111d64..d74a7a5928 100644 --- a/src/cli/utils/runner.js +++ b/src/cli/utils/runner.js @@ -1,20 +1,13 @@ import program from './commander'; function logStartupOptions(options) { - if (!options.verbose) { - return; - } - // Keys that may include sensitive information that will be redacted in logs - const keysToRedact = [ - 'databaseURI', - 'masterKey', - 'maintenanceKey', - 'push', - ]; for (const key in options) { let value = options[key]; - if (keysToRedact.includes(key)) { - value = ''; + if (key == 'masterKey') { + value = '***REDACTED***'; + } + if (key == 'push' && options.verbose != true) { + value = '***REDACTED***'; } if (typeof value === 'object') { try { diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index e37cc9b225..01bf65f42c 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -1,5 +1,6 @@ import { Parse } from 'parse/node'; import * as triggers from '../triggers'; +import Deprecator from '../Deprecator/Deprecator'; import { addRateLimit } from '../middlewares'; const Config = require('../Config'); @@ -501,6 +502,130 @@ ParseCloud.afterFind = function (parseClass, handler, validationHandler) { ); }; +/** + * Registers a before save file function. + * + * **Available in Cloud Code only.** + * + * ``` + * Parse.Cloud.beforeSaveFile(async (request) => { + * // code here + * }, (request) => { + * // validation code here + * }); + * + * Parse.Cloud.beforeSaveFile(async (request) => { + * // code here + * }, { ...validationObject }); + *``` + * + * @method beforeSaveFile + * @deprecated + * @name Parse.Cloud.beforeSaveFile + * @param {Function} func The function to run before saving a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. + * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. + */ +ParseCloud.beforeSaveFile = function (handler, validationHandler) { + Deprecator.logRuntimeDeprecation({ + usage: 'Parse.Cloud.beforeSaveFile', + solution: 'Use Parse.Cloud.beforeSave(Parse.File, (request) => {})', + }); + ParseCloud.beforeSave(Parse.File, handler, validationHandler); +}; + +/** + * Registers an after save file function. + * + * **Available in Cloud Code only.** + * + * ``` + * Parse.Cloud.afterSaveFile(async (request) => { + * // code here + * }, (request) => { + * // validation code here + * }); + * + * Parse.Cloud.afterSaveFile(async (request) => { + * // code here + * }, { ...validationObject }); + *``` + * + * @method afterSaveFile + * @deprecated + * @name Parse.Cloud.afterSaveFile + * @param {Function} func The function to run after saving a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. + * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. + */ +ParseCloud.afterSaveFile = function (handler, validationHandler) { + Deprecator.logRuntimeDeprecation({ + usage: 'Parse.Cloud.afterSaveFile', + solution: 'Use Parse.Cloud.afterSave(Parse.File, (request) => {})', + }); + ParseCloud.afterSave(Parse.File, handler, validationHandler); +}; + +/** + * Registers a before delete file function. + * + * **Available in Cloud Code only.** + * + * ``` + * Parse.Cloud.beforeDeleteFile(async (request) => { + * // code here + * }, (request) => { + * // validation code here + * }); + * + * Parse.Cloud.beforeDeleteFile(async (request) => { + * // code here + * }, { ...validationObject }); + *``` + * + * @method beforeDeleteFile + * @deprecated + * @name Parse.Cloud.beforeDeleteFile + * @param {Function} func The function to run before deleting a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. + * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. + */ +ParseCloud.beforeDeleteFile = function (handler, validationHandler) { + Deprecator.logRuntimeDeprecation({ + usage: 'Parse.Cloud.beforeDeleteFile', + solution: 'Use Parse.Cloud.beforeDelete(Parse.File, (request) => {})', + }); + ParseCloud.beforeDelete(Parse.File, handler, validationHandler); +}; + +/** + * Registers an after delete file function. + * + * **Available in Cloud Code only.** + * + * ``` + * Parse.Cloud.afterDeleteFile(async (request) => { + * // code here + * }, (request) => { + * // validation code here + * }); + * + * Parse.Cloud.afterDeleteFile(async (request) => { + * // code here + * }, { ...validationObject }); + *``` + * + * @method afterDeleteFile + * @deprecated + * @name Parse.Cloud.afterDeleteFile + * @param {Function} func The function to after before deleting a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. + * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. + */ +ParseCloud.afterDeleteFile = function (handler, validationHandler) { + Deprecator.logRuntimeDeprecation({ + usage: 'Parse.Cloud.afterDeleteFile', + solution: 'Use Parse.Cloud.afterDelete(Parse.File, (request) => {})', + }); + ParseCloud.afterDelete(Parse.File, handler, validationHandler); +}; + /** * Registers a before live query server connect function. * @@ -678,7 +803,7 @@ module.exports = ParseCloud; * @property {Integer} contentLength The value from Content-Length header * @property {String} ip The IP address of the client making the request. * @property {Object} headers The original HTTP headers for the request. - * @property {String} triggerName The name of the trigger (`beforeSave`, `afterSave`) + * @property {String} triggerName The name of the trigger (`beforeSaveFile`, `afterSaveFile`) * @property {Object} log The current logger inside Parse Server. */ diff --git a/src/index.js b/src/index.js index 0c9069d6b5..dcfe9b4c7e 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ 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'; import { PushWorker } from './Push/PushWorker'; diff --git a/src/middlewares.js b/src/middlewares.js index d4edb37760..a7e309b0cc 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -10,9 +10,9 @@ import PostgresStorageAdapter from './Adapters/Storage/Postgres/PostgresStorageA 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'; -import { BlockList, isIPv4 } from 'net'; 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'; @@ -23,46 +23,6 @@ const getMountForRequest = function (req) { return req.protocol + '://' + req.get('host') + mountPath; }; -const getBlockList = (ipRangeList, store) => { - if (store.get('blockList')) return store.get('blockList'); - const blockList = new BlockList(); - ipRangeList.forEach(fullIp => { - if (fullIp === '::/0' || fullIp === '::') { - store.set('allowAllIpv6', true); - return; - } - if (fullIp === '0.0.0.0/0' || fullIp === '0.0.0.0') { - store.set('allowAllIpv4', true); - return; - } - const [ip, mask] = fullIp.split('/'); - if (!mask) { - blockList.addAddress(ip, isIPv4(ip) ? 'ipv4' : 'ipv6'); - } else { - blockList.addSubnet(ip, Number(mask), isIPv4(ip) ? 'ipv4' : 'ipv6'); - } - }); - store.set('blockList', blockList); - return blockList; -}; - -export const checkIp = (ip, ipRangeList, store) => { - const incomingIpIsV4 = isIPv4(ip); - const blockList = getBlockList(ipRangeList, store); - - if (store.get(ip)) return true; - if (store.get('allowAllIpv4') && incomingIpIsV4) return true; - if (store.get('allowAllIpv6') && !incomingIpIsV4) return true; - const result = blockList.check(ip, incomingIpIsV4 ? 'ipv4' : 'ipv6'); - - // If the ip is in the list, we store the result in the store - // so we have a optimized path for the next request - if (ipRangeList.includes(ip) && result) { - store.set(ip, result); - } - return result; -}; - // Checks that the request is authorized for this app and checks user // auth too. // The bodyparser should run before this middleware. @@ -223,7 +183,7 @@ export function handleParseHeaders(req, res, next) { const isMaintenance = req.config.maintenanceKey && info.maintenanceKey === req.config.maintenanceKey; if (isMaintenance) { - if (checkIp(clientIp, req.config.maintenanceKeyIps || [], req.config.maintenanceKeyIpsStore)) { + if (ipRangeCheck(clientIp, req.config.maintenanceKeyIps || [])) { req.auth = new auth.Auth({ config: req.config, installationId: info.installationId, @@ -239,8 +199,7 @@ export function handleParseHeaders(req, res, next) { } let isMaster = info.masterKey === req.config.masterKey; - - if (isMaster && !checkIp(clientIp, req.config.masterKeyIps || [], req.config.masterKeyIpsStore)) { + if (isMaster && !ipRangeCheck(clientIp, req.config.masterKeyIps || [])) { const log = req.config?.loggerController || defaultLogger; log.error( `Request using master key rejected as the request IP address '${clientIp}' is not set in Parse Server option 'masterKeyIps'.` @@ -342,7 +301,7 @@ const handleRateLimit = async (req, res, next) => { export const handleParseSession = async (req, res, next) => { try { const info = req.info; - if (req.auth || req.url === '/sessions/me') { + if (req.auth) { next(); return; } diff --git a/src/rest.js b/src/rest.js index 1f9dbacb73..e1e53668a6 100644 --- a/src/rest.js +++ b/src/rest.js @@ -12,7 +12,6 @@ var Parse = require('parse/node').Parse; var RestQuery = require('./RestQuery'); var RestWrite = require('./RestWrite'); var triggers = require('./triggers'); -const { enforceRoleSecurity } = require('./SharedRest'); function checkTriggers(className, config, types) { return types.some(triggerType => { @@ -25,34 +24,65 @@ function checkLiveQuery(className, config) { } // Returns a promise for an object with optional keys 'results' and 'count'. -const find = async (config, auth, className, restWhere, restOptions, clientSDK, context) => { - const query = await RestQuery({ - method: RestQuery.Method.find, - config, - auth, - className, - restWhere, - restOptions, - clientSDK, - context, - }); - return query.execute(); -}; +function find(config, auth, className, restWhere, restOptions, clientSDK, context) { + enforceRoleSecurity('find', className, auth); + return triggers + .maybeRunQueryTrigger( + triggers.Types.beforeFind, + className, + restWhere, + restOptions, + config, + auth, + context + ) + .then(result => { + restWhere = result.restWhere || restWhere; + restOptions = result.restOptions || restOptions; + const query = new RestQuery( + config, + auth, + className, + restWhere, + restOptions, + clientSDK, + true, + context + ); + return query.execute(); + }); +} // get is just like find but only queries an objectId. -const get = async (config, auth, className, objectId, restOptions, clientSDK, context) => { +const get = (config, auth, className, objectId, restOptions, clientSDK, context) => { var restWhere = { objectId }; - const query = await RestQuery({ - method: RestQuery.Method.get, - config, - auth, - className, - restWhere, - restOptions, - clientSDK, - context, - }); - return query.execute(); + enforceRoleSecurity('get', className, auth); + return triggers + .maybeRunQueryTrigger( + triggers.Types.beforeFind, + className, + restWhere, + restOptions, + config, + auth, + context, + true + ) + .then(result => { + restWhere = result.restWhere || restWhere; + restOptions = result.restOptions || restOptions; + const query = new RestQuery( + config, + auth, + className, + restWhere, + restOptions, + clientSDK, + true, + context + ); + return query.execute(); + }); }; // Returns a promise that doesn't resolve to any useful value. @@ -71,40 +101,35 @@ function del(config, auth, className, objectId, context) { let schemaController; return Promise.resolve() - .then(async () => { + .then(() => { const hasTriggers = checkTriggers(className, config, ['beforeDelete', 'afterDelete']); const hasLiveQuery = checkLiveQuery(className, config); if (hasTriggers || hasLiveQuery || className == '_Session') { - const query = await RestQuery({ - method: RestQuery.Method.get, - config, - auth, - className, - restWhere: { objectId }, - }); - return query.execute({ op: 'delete' }).then(response => { - if (response && response.results && response.results.length) { - const firstResult = response.results[0]; - firstResult.className = className; - if (className === '_Session' && !auth.isMaster && !auth.isMaintenance) { - if (!auth.user || firstResult.user.objectId !== auth.user.id) { - throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token'); + return new RestQuery(config, auth, className, { objectId }) + .execute({ op: 'delete' }) + .then(response => { + if (response && response.results && response.results.length) { + const firstResult = response.results[0]; + firstResult.className = className; + if (className === '_Session' && !auth.isMaster && !auth.isMaintenance) { + if (!auth.user || firstResult.user.objectId !== auth.user.id) { + throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token'); + } } + var cacheAdapter = config.cacheController; + cacheAdapter.user.del(firstResult.sessionToken); + inflatedObject = Parse.Object.fromJSON(firstResult); + return triggers.maybeRunTrigger( + triggers.Types.beforeDelete, + auth, + inflatedObject, + null, + config, + context + ); } - var cacheAdapter = config.cacheController; - cacheAdapter.user.del(firstResult.sessionToken); - inflatedObject = Parse.Object.fromJSON(firstResult); - return triggers.maybeRunTrigger( - triggers.Types.beforeDelete, - auth, - inflatedObject, - null, - config, - context - ); - } - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found for delete.'); - }); + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found for delete.'); + }); } return Promise.resolve({}); }) @@ -168,22 +193,21 @@ function update(config, auth, className, restWhere, restObject, clientSDK, conte enforceRoleSecurity('update', className, auth); return Promise.resolve() - .then(async () => { + .then(() => { const hasTriggers = checkTriggers(className, config, ['beforeSave', 'afterSave']); const hasLiveQuery = checkLiveQuery(className, config); if (hasTriggers || hasLiveQuery) { // Do not use find, as it runs the before finds - const query = await RestQuery({ - method: RestQuery.Method.get, + return new RestQuery( config, auth, className, restWhere, - runAfterFind: false, - runBeforeFind: false, - context, - }); - return query.execute({ + undefined, + undefined, + false, + context + ).execute({ op: 'update', }); } @@ -224,6 +248,40 @@ function handleSessionMissingError(error, className, auth) { throw error; } +const classesWithMasterOnlyAccess = [ + '_JobStatus', + '_PushStatus', + '_Hooks', + '_GlobalConfig', + '_JobSchedule', + '_Idempotency', +]; +// Disallowing access to the _Role collection except by master key +function enforceRoleSecurity(method, className, auth) { + if (className === '_Installation' && !auth.isMaster && !auth.isMaintenance) { + if (method === 'delete' || method === 'find') { + const error = `Clients aren't allowed to perform the ${method} operation on the installation collection.`; + throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); + } + } + + //all volatileClasses are masterKey only + if ( + classesWithMasterOnlyAccess.indexOf(className) >= 0 && + !auth.isMaster && + !auth.isMaintenance + ) { + const error = `Clients aren't allowed to perform the ${method} operation on the ${className} collection.`; + throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); + } + + // readOnly masterKey is not allowed + if (auth.isReadOnly && (method === 'delete' || method === 'create' || method === 'update')) { + const error = `read-only masterKey isn't allowed to perform the ${method} operation.`; + throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, error); + } +} + module.exports = { create, del, diff --git a/src/triggers.js b/src/triggers.js index 5c4755af54..b5f11435df 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -270,8 +270,6 @@ export function getRequestObject( triggerType === Types.afterSave || triggerType === Types.beforeDelete || triggerType === Types.afterDelete || - triggerType === Types.beforeLogin || - triggerType === Types.afterLogin || triggerType === Types.afterFind ) { // Set a copy of the context on the request object.