diff --git a/.artifacts/zitadel/.gitignore b/.artifacts/zitadel/.gitignore deleted file mode 100644 index bf27f3114..000000000 --- a/.artifacts/zitadel/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!.gitkeep diff --git a/.dockerignore b/.dockerignore index 0fea51423..d00754562 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ -/.git/ +# .git .codecov -/.github/ +.github .gitignore .dockerignore **/Dockerfile @@ -15,8 +15,14 @@ CONTRIBUTING.md LICENSE README.md SECURITY.md +**/Dockerfile +**/*.Dockerfile pkg/grpc/*/*.pb.* pkg/grpc/*/*.swagger.json -.goreleaser.yaml -.artifacts/ +**/.artifacts +console/.angular +console/node_modules +console/src/app/proto/generated/ +console/tmp/ .vscode +build/*.Dockerfile \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..2646f5258 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,99 @@ +name: ZITADEL CI/CD + +on: + push: + tags-ignore: + - "*" + branches: + - "**" + pull_request: + merge_group: + workflow_dispatch: + +permissions: + contents: write + packages: write + +jobs: + + core: + uses: ./.github/workflows/core.yml + with: + node_version: '18' + buf_version: 'latest' + go_version: '1.20' + + console: + uses: ./.github/workflows/console.yml + with: + node_version: '18' + buf_version: 'latest' + + version: + uses: ./.github/workflows/version.yml + with: + semantic_version: '19.0.2' + dry_run: true + + compile: + needs: [core, console, version] + uses: ./.github/workflows/compile.yml + with: + go_version: '1.20' + core_cache_key: ${{ needs.core.outputs.cache_key }} + console_cache_key: ${{ needs.console.outputs.cache_key }} + core_cache_path: ${{ needs.core.outputs.cache_path }} + console_cache_path: ${{ needs.console.outputs.cache_path }} + version: ${{ needs.version.outputs.version }} + + core-unit-test: + needs: core + uses: ./.github/workflows/core-unit-test.yml + with: + go_version: '1.20' + core_cache_key: ${{ needs.core.outputs.cache_key }} + core_cache_path: ${{ needs.core.outputs.cache_path }} + + core-integration-test: + needs: core + uses: ./.github/workflows/core-integration-test.yml + with: + go_version: '1.20' + core_cache_key: ${{ needs.core.outputs.cache_key }} + core_cache_path: ${{ needs.core.outputs.cache_path }} + + lint: + needs: [core, console] + uses: ./.github/workflows/lint.yml + with: + go_version: '1.20' + node_version: '18' + buf_version: 'latest' + go_lint_version: 'v1.53.2' + core_cache_key: ${{ needs.core.outputs.cache_key }} + core_cache_path: ${{ needs.core.outputs.cache_path }} + + container: + needs: [compile] + uses: ./.github/workflows/container.yml + with: + image_name: 'ghcr.io/zitadel/zitadel' + + e2e: + uses: ./.github/workflows/e2e.yml + needs: [container] + with: + image: ${{ needs.container.outputs.image }}-debug + + release: + uses: ./.github/workflows/release.yml + needs: [version, core-unit-test, core-integration-test, lint, container, e2e] + # TODO: trigger release on workflow_dispatch if: ${{ github.event_name == 'workflow_dispatch' }} + if: ${{ needs.version.outputs.published == 'true' }} + secrets: + GCR_JSON_KEY_BASE64: ${{ secrets.GCR_JSON_KEY_BASE64 }} + with: + image: ${{ needs.container.outputs.image }} + semantic_version: '19.0.2' + image_name: 'ghcr.io/zitadel/zitadel' + google_image_name: "europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql.yml similarity index 97% rename from .github/workflows/codeql-analysis.yml rename to .github/workflows/codeql.yml index 6ca453c32..57059f1b6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql.yml @@ -1,4 +1,4 @@ -name: "Code scanning - action" +name: "Code Scanning" on: push: diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml new file mode 100644 index 000000000..10baaae96 --- /dev/null +++ b/.github/workflows/compile.yml @@ -0,0 +1,99 @@ +name: Compile + +on: + workflow_call: + inputs: + go_version: + required: true + type: string + core_cache_key: + required: true + type: string + core_cache_path: + required: true + type: string + console_cache_key: + required: true + type: string + console_cache_path: + required: true + type: string + version: + required: true + type: string + +jobs: + executable: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + goos: [linux, darwin, windows] + goarch: [amd64, arm64] + + steps: + - + uses: actions/checkout@v3 + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + name: restore console + with: + path: ${{ inputs.console_cache_path }} + key: ${{ inputs.console_cache_key }} + fail-on-cache-miss: true + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + name: restore core + with: + path: ${{ inputs.core_cache_path }} + key: ${{ inputs.core_cache_key }} + fail-on-cache-miss: true + - + uses: actions/setup-go@v4 + with: + go-version: ${{ inputs.go_version }} + - + name: compile + timeout-minutes: 5 + run: | + GOOS="${{matrix.goos}}" \ + GOARCH="${{matrix.goarch}}" \ + VERSION="${{ inputs.version }}" \ + COMMIT_SHA="${{ github.sha }}" \ + make compile_pipeline + - + name: create folder + run: | + mkdir zitadel-${{ matrix.goos }}-${{ matrix.goarch }} + mv zitadel zitadel-${{ matrix.goos }}-${{ matrix.goarch }}/ + cp LICENSE zitadel-${{ matrix.goos }}-${{ matrix.goarch }}/ + cp README.md zitadel-${{ matrix.goos }}-${{ matrix.goarch }}/ + tar -cvf zitadel-${{ matrix.goos }}-${{ matrix.goarch }}.tar zitadel-${{ matrix.goos }}-${{ matrix.goarch }} + - + uses: actions/upload-artifact@v3 + with: + name: zitadel-${{ matrix.goos }}-${{ matrix.goarch }} + path: zitadel-${{ matrix.goos }}-${{ matrix.goarch }}.tar + + checksums: + runs-on: ubuntu-latest + needs: executable + steps: + - + uses: actions/download-artifact@v3 + with: + path: executables + - + name: move files one folder up + run: mv */*.tar . && find . -type d -empty -delete + working-directory: executables + - + run: sha256sum * > checksums.txt + working-directory: executables + - + uses: actions/upload-artifact@v3 + with: + name: checksums.txt + path: executables/checksums.txt diff --git a/.github/workflows/console.yml b/.github/workflows/console.yml new file mode 100644 index 000000000..1c19982ac --- /dev/null +++ b/.github/workflows/console.yml @@ -0,0 +1,61 @@ +name: Build console + +on: + workflow_call: + inputs: + node_version: + required: true + type: string + buf_version: + required: true + type: string + outputs: + cache_key: + value: ${{ jobs.build.outputs.cache_key }} + cache_path: + value: ${{ jobs.build.outputs.cache_path }} + +env: + cache_path: console/dist/console + +jobs: + build: + outputs: + cache_key: ${{ steps.cache.outputs.cache-primary-key }} + cache_path: ${{ env.cache_path }} + runs-on: ubuntu-latest + steps: + - + uses: actions/checkout@v3 + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + id: cache + with: + key: console-${{ hashFiles('console', 'proto') }} + restore-keys: | + console- + path: ${{ env.cache_path }} + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: bufbuild/buf-setup-action@v1 + with: + github_token: ${{ github.token }} + version: ${{ inputs.buf_version }} + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: actions/setup-node@v3 + with: + node-version: ${{ inputs.node_version }} + cache: 'yarn' + cache-dependency-path: console/yarn.lock + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + run: make console_build + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: actions/cache/save@v3 + with: + path: ${{ env.cache_path }} + key: ${{ steps.cache.outputs.cache-primary-key }} + \ No newline at end of file diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml new file mode 100644 index 000000000..6660ee8ec --- /dev/null +++ b/.github/workflows/container.yml @@ -0,0 +1,168 @@ +name: Container + +on: + workflow_call: + inputs: + image_name: + required: true + type: string + outputs: + image: + value: '${{ inputs.image_name }}:${{ github.sha }}' + +env: + default_labels: | + org.opencontainers.image.documentation=https://zitadel.com/docs + org.opencontainers.image.vendor=CAOS AG + +jobs: + build: + name: zitadel + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + arch: [amd64,arm64] + steps: + - + uses: actions/checkout@v3 + - + name: Scratch meta + id: scratch-meta + uses: docker/metadata-action@v4 + with: + images: ${{ inputs.image_name }} + labels: ${{ env.default_labels}} + tags: | + type=sha,prefix=,suffix=,format=long + - + name: Debug meta + id: debug-meta + uses: docker/metadata-action@v4 + with: + images: ${{ inputs.image_name }} + labels: ${{ env.default_labels}} + tags: | + type=sha,prefix=,suffix=-debug,format=long + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + driver-opts: 'image=moby/buildkit:v0.11.6' + - + name: Login to Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + uses: actions/download-artifact@v3 + with: + path: .artifacts + name: zitadel-linux-${{ matrix.arch }} + - + name: Unpack executable + run: | + tar -xvf .artifacts/zitadel-linux-${{ matrix.arch }}.tar + mv zitadel-linux-${{ matrix.arch }}/zitadel ./zitadel + - + name: Debug + id: build-debug + uses: docker/build-push-action@v4 + timeout-minutes: 3 + with: + context: . + file: build/Dockerfile + target: artifact + platforms: linux/${{ matrix.arch }} + push: true + labels: ${{ steps.debug-meta.outputs.labels }} + outputs: type=image,name=${{ inputs.image_name }},push-by-digest=true,name-canonical=true,push=true + - + name: Scratch + id: build-scratch + uses: docker/build-push-action@v4 + timeout-minutes: 3 + with: + context: . + file: build/Dockerfile + target: final + platforms: linux/${{ matrix.arch }} + push: true + labels: ${{ steps.scratch-meta.outputs.labels }} + outputs: type=image,name=${{ inputs.image_name }},push-by-digest=true,name-canonical=true,push=true + - + name: Export debug digest + run: | + mkdir -p /tmp/digests/debug + digest="${{ steps.build-debug.outputs.digest }}" + touch "/tmp/digests/debug/${digest#sha256:}" + - + name: Export scratch digest + run: | + mkdir -p /tmp/digests/scratch + digest="${{ steps.build-scratch.outputs.digest }}" + touch "/tmp/digests/scratch/${digest#sha256:}" + - + name: Upload digest + uses: actions/upload-artifact@v3 + with: + name: digests + path: /tmp/digests + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: + - build + strategy: + fail-fast: false + matrix: + image: [scratch, debug] + include: + - image: scratch + suffix: '' + - image: debug + suffix: '-debug' + steps: + - + name: Download digests + uses: actions/download-artifact@v3 + with: + name: digests + path: /tmp/digests + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + driver-opts: 'image=moby/buildkit:v0.11.6' + - + name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: '${{ inputs.image_name }}' + tags: | + type=sha,prefix=,suffix=${{ matrix.suffix }},format=long + - + name: Login to Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Create manifest list and push + working-directory: /tmp/digests/${{ matrix.image }} + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ inputs.image_name }}@sha256:%s ' *) + - + name: Inspect image + run: | + docker buildx imagetools inspect ${{ inputs.image_name }}:${{ github.sha }}${{ matrix.suffix }} diff --git a/.github/workflows/core-integration-test.yml b/.github/workflows/core-integration-test.yml new file mode 100644 index 000000000..c99987d25 --- /dev/null +++ b/.github/workflows/core-integration-test.yml @@ -0,0 +1,153 @@ +name: Integration test core + +on: + workflow_call: + inputs: + go_version: + required: true + type: string + core_cache_key: + required: true + type: string + core_cache_path: + required: true + type: string + +jobs: + postgres: + runs-on: ubuntu-latest + services: + postgres: + image: postgres + ports: + - 5432:5432 + env: + POSTGRES_USER: zitadel + PGUSER: zitadel + POSTGRES_DB: zitadel + POSTGRES_HOST_AUTH_METHOD: trust + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + --health-start-period 10s + steps: + - + uses: actions/checkout@v3 + - + uses: actions/setup-go@v4 + with: + go-version: ${{ inputs.go_version }} + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + name: restore core + id: restore-core + with: + path: ${{ inputs.core_cache_path }} + key: ${{ inputs.core_cache_key }} + fail-on-cache-miss: true + - + id: go-cache-path + name: set cache path + run: echo "GO_CACHE_PATH=$(go env GOCACHE)" >> $GITHUB_OUTPUT + - + uses: actions/cache/restore@v3 + id: cache + timeout-minutes: 1 + name: restore previous results + with: + key: integration-test-postgres-${{ inputs.core_cache_key }} + restore-keys: | + integration-test-postgres-core- + path: ${{ steps.go-cache-path.outputs.GO_CACHE_PATH }} + - + name: test + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + env: + ZITADEL_MASTERKEY: MasterkeyNeedsToHave32Characters + INTEGRATION_DB_FLAVOR: postgres + run: make core_integration_test + - + name: publish coverage + uses: codecov/codecov-action@v3.1.4 + with: + file: profile.cov + name: core-integration-tests-postgres + flags: core-integration-tests-postgres + - + uses: actions/cache/save@v3 + name: cache results + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + with: + key: integration-test-postgres-${{ inputs.core_cache_key }} + path: ${{ steps.go-cache-path.outputs.GO_CACHE_PATH }} + + # TODO: enable as soon as cockroach allows `COCKROACH_ARGS` + # cockroach: + # runs-on: ubuntu-latest + # services: + # cockroach: + # image: cockroachdb/cockroach:latest + # ports: + # - 26257:26257 + # - 9090:9090 + # env: + # COCKROACH_ARGS: start-single-node --insecure --http-addr :9090 + # options: >- + # --health-cmd "curl http://localhost:9090/health?ready=1 || exit 1" + # --health-interval 10s + # --health-timeout 5s + # --health-retries 5 + # --health-start-period 10s + # steps: + # - + # uses: actions/checkout@v3 + # - + # uses: actions/setup-go@v4 + # with: + # go-version: ${{ inputs.go_version }} + # - + # uses: actions/cache/restore@v3 + # timeout-minutes: 1 + # name: restore core + # with: + # path: ${{ inputs.core_cache_path }} + # key: ${{ inputs.core_cache_key }} + # fail-on-cache-miss: true + # - + # id: go-cache-path + # name: set cache path + # run: echo "GO_CACHE_PATH=$(go env GOCACHE)" >> $GITHUB_OUTPUT + # - + # uses: actions/cache/restore@v3 + # timeout-minutes: 1 + # name: restore previous results + # cache: id + # with: + # key: integration-test-crdb-${{ inputs.core_cache_key }} + # restore-keys: | + # integration-test-crdb-core- + # path: ${{ steps.go-cache-path.outputs.GO_CACHE_PATH }} + # - + # name: test + # if: ${{ steps.cache.outputs.cache-hit != 'true' }} + # env: + # ZITADEL_MASTERKEY: MasterkeyNeedsToHave32Characters + # INTEGRATION_DB_FLAVOR: cockroach + # run: make core_integration_test + # - + # name: publish coverage + # uses: codecov/codecov-action@v3.1.4 + # with: + # file: profile.cov + # name: core-integration-tests-cockroach + # flags: core-integration-tests-cockroach + # - + # uses: actions/cache/save@v3 + # name: cache results + # if: ${{ steps.cache.outputs.cache-hit != 'true' }} + # with: + # key: integration-test-crdb-${{ inputs.core_cache_key }} + # path: ${{ steps.go-cache-path.outputs.GO_CACHE_PATH }} \ No newline at end of file diff --git a/.github/workflows/core-unit-test.yml b/.github/workflows/core-unit-test.yml new file mode 100644 index 000000000..c831758d4 --- /dev/null +++ b/.github/workflows/core-unit-test.yml @@ -0,0 +1,67 @@ +name: Unit test core + +on: + workflow_call: + inputs: + go_version: + required: true + type: string + core_cache_key: + required: true + type: string + core_cache_path: + required: true + type: string + +jobs: + test: + runs-on: ubuntu-latest + steps: + - + uses: actions/checkout@v3 + - + uses: actions/setup-go@v4 + with: + go-version: ${{ inputs.go_version }} + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + name: restore core + id: restore-core + with: + path: ${{ inputs.core_cache_path }} + key: ${{ inputs.core_cache_key }} + fail-on-cache-miss: true + - + id: go-cache-path + name: set cache path + run: echo "GO_CACHE_PATH=$(go env GOCACHE)" >> $GITHUB_OUTPUT + - + uses: actions/cache/restore@v3 + id: cache + timeout-minutes: 1 + name: restore previous results + with: + key: unit-test-${{ inputs.core_cache_key }} + restore-keys: | + unit-test-core- + path: ${{ steps.go-cache-path.outputs.GO_CACHE_PATH }} + - + name: test + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + run: make core_unit_test + - + name: publish coverage + uses: codecov/codecov-action@v3.1.4 + with: + file: profile.cov + name: core-unit-tests + flags: core-unit-tests + - + uses: actions/cache/save@v3 + name: cache results + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + with: + key: unit-test-${{ inputs.core_cache_key }} + path: ${{ steps.go-cache-path.outputs.GO_CACHE_PATH }} + \ No newline at end of file diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml new file mode 100644 index 000000000..c5d868533 --- /dev/null +++ b/.github/workflows/core.yml @@ -0,0 +1,81 @@ +name: Build core + +on: + workflow_call: + inputs: + go_version: + required: true + type: string + buf_version: + required: true + type: string + node_version: + required: true + type: string + outputs: + cache_key: + value: ${{ jobs.build.outputs.cache_key }} + cache_path: + value: ${{ jobs.build.outputs.cache_path }} + +env: + cache_path: | + internal/statik/statik.go + internal/notification/statik/statik.go + internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css* + internal/api/ui/login/statik/statik.go + internal/api/assets/authz.go + internal/api/assets/router.go + openapi/v2 + pkg/grpc/**/*.pb.* + +jobs: + build: + runs-on: ubuntu-latest + outputs: + cache_key: ${{ steps.cache.outputs.cache-primary-key }} + cache_path: ${{ env.cache_path }} + steps: + - + uses: actions/checkout@v3 + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + id: cache + with: + key: core-${{ hashFiles( 'go.*', 'openapi', 'cmd', 'pkg/grpc/**/*.go', 'proto', 'internal') }} + restore-keys: | + core- + path: ${{ env.cache_path }} + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: bufbuild/buf-setup-action@v1 + with: + github_token: ${{ github.token }} + version: ${{ inputs.buf_version }} + + - + # node to install sass + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: actions/setup-node@v3 + with: + node-version: ${{ inputs.node_version }} + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + run: npm install -g sass + + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: actions/setup-go@v4 + with: + go-version: ${{ inputs.go_version }} + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + run: make core_build + - + if: ${{ steps.cache.outputs.cache-hit != 'true' }} + uses: actions/cache/save@v3 + with: + key: ${{ steps.cache.outputs.cache-primary-key }} + path: ${{ env.cache_path }} + \ No newline at end of file diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 50f1ce85c..e3324cbb2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,66 +1,104 @@ name: "ZITADEL e2e Tests" on: - workflow_run: - workflows: [ZITADEL Release] - types: - - completed - workflow_dispatch: + workflow_call: inputs: - releaseversion: - description: 'Release version to test' + image: required: true - default: 'latest' + type: string jobs: test: strategy: + fail-fast: false matrix: browser: [firefox, chrome] - runs-on: ubuntu-20.04 + services: + # we currently use postgres because cockroach doesn't work + postgres: + image: postgres + ports: + - 5432:5432 + env: + POSTGRES_USER: zitadel + PGUSER: zitadel + POSTGRES_DB: zitadel + POSTGRES_HOST_AUTH_METHOD: trust + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + --health-start-period 10s + zitadel: + image: ${{ inputs.image }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + options: >- + --health-cmd "zitadel ready" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + --health-start-period 10s + --add-host host.docker.internal:host-gateway + ports: + - 8080:8080 + env: + ZITADEL_ARGS: "start-from-init --masterkeyFromEnv" + ZITADEL_MASTERKEY: MasterkeyNeedsToHave32Characters + ZITADEL_LOG_LEVEL: debug + ZITADEL_EXTERNALDOMAIN: localhost + ZITADEL_EXTERNALSECURE: "false" + ZITADEL_TLS_ENABLED: "false" + ZITADEL_DATABASE_POSTGRES_HOST: postgres + ZITADEL_DATABASE_POSTGRES_PORT: "5432" + ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel + ZITADEL_DATABASE_POSTGRES_MAXOPENCONNS: "20" + ZITADEL_DATABASE_POSTGRES_MAXIDLECONNS: "10" + ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel + ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable + ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: zitadel + ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable + ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: "false" + ZITADEL_LOGSTORE_ACCESS_DATABASE_ENABLED: "true" + ZITADEL_LOGSTORE_ACCESS_DATABASE_DEBOUNCE_MINFREQUENCY: 0s + ZITADEL_LOGSTORE_ACCESS_DATABASE_DEBOUNCE_MAXBULKSIZE: "0" + ZITADEL_LOGSTORE_EXECUTION_DATABASE_ENABLED: "true" + ZITADEL_LOGSTORE_EXECUTION_STDOUT_ENABLED: "false" + ZITADEL_QUOTAS_ACCESS_EXHAUSTEDCOOKIEKEY: "zitadel.quota.limiting" + ZITADEL_QUOTAS_ACCESS_EXHAUSTEDCOOKIEMAXAGE: 60s + ZITADEL_PROJECTIONS_CUSTOMIZATIONS_NOTIFICATIONSQUOTAS_REQUEUEEVERY: 1s + ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_MFAINITSKIPLIFETIME: "0" + ZITADEL_SYSTEMAPIUSERS: "{\"cypress\": {\"keyData\": \"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF6aStGRlNKTDdmNXl3NEtUd3pnTQpQMzRlUEd5Y20vTStrVDBNN1Y0Q2d4NVYzRWFESXZUUUtUTGZCYUVCNDV6YjlMdGpJWHpEdzByWFJvUzJoTzZ0CmgrQ1lRQ3ozS0N2aDA5QzBJenhaaUIySVMzSC9hVCs1Qng5RUZZK3ZuQWtaamNjYnlHNVlOUnZtdE9sbnZJZUkKSDdxWjB0RXdrUGZGNUdFWk5QSlB0bXkzVUdWN2lvZmRWUVMxeFJqNzMrYU13NXJ2SDREOElkeWlBQzNWZWtJYgpwdDBWajBTVVgzRHdLdG9nMzM3QnpUaVBrM2FYUkYwc2JGaFFvcWRKUkk4TnFnWmpDd2pxOXlmSTV0eXhZc3duCitKR3pIR2RIdlczaWRPRGxtd0V0NUsycGFzaVJJV0syT0dmcSt3MEVjbHRRSGFidXFFUGdabG1oQ2tSZE5maXgKQndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==\"}}" + + runs-on: ubuntu-latest env: - ZITADEL_IMAGE_REGISTRY: 'ghcr.io/zitadel/zitadel' + ZITADEL_IMAGE: ${{ inputs.image }} steps: - - name: Checkout Repository + - + name: Checkout Repository uses: actions/checkout@v3 - - name: Set TAG env manual trigger - if: github.event_name == 'workflow_dispatch' - run: echo "ZITADEL_IMAGE=${ZITADEL_IMAGE_REGISTRY}:${{ github.event.inputs.releaseversion }}" >> $GITHUB_ENV - - name: get latest tag - uses: actions-ecosystem/action-get-latest-tag@v1 - id: get-latest-tag - with: - semver_only: true - - name: Set TAG env on ZITADEL release - if: github.event_name == 'workflow_run' - run: echo "ZITADEL_IMAGE=${ZITADEL_IMAGE_REGISTRY}:${{ steps.get-latest-tag.outputs.tag }}" >> $GITHUB_ENV - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + - + name: Cypress run + uses: cypress-io/github-action@v5 + env: + CYPRESS_BASE_URL: http://localhost:8080/ui/console + CYPRESS_WEBHOOK_HANDLER_HOST: host.docker.internal + CYPRESS_DATABASE_CONNECTION_URL: 'postgresql://zitadel@localhost:5432/zitadel' + CYPRESS_BACKEND_URL: http://localhost:8080 with: - driver: docker - install: true - - name: Test ${{ matrix.browser }} - run: docker compose run --service-ports e2e --browser ${{ matrix.browser }} - working-directory: e2e/config/host.docker.internal - - name: Ensure Artifacts Directory Exists - run: mkdir -p ./.artifacts - - name: Save ZITADEL Logs - if: always() - run: docker compose logs zitadel > ../../../.artifacts/e2e-compose-zitadel.log - working-directory: e2e/config/host.docker.internal - - name: Save Prepare Logs - if: always() - run: docker compose logs prepare > ../../../.artifacts/e2e-compose-prepare.log - working-directory: e2e/config/host.docker.internal - - name: Archive production tests ${{ matrix.browser }} - if: always() + working-directory: e2e + browser: ${{ matrix.browser }} + command: npm run e2e + config-file: cypress.config.ts + - uses: actions/upload-artifact@v3 + if: always() with: name: production-tests-${{ matrix.browser }} path: | - e2e/cypress/results - e2e/cypress/videos e2e/cypress/screenshots - .artifacts/e2e-compose-zitadel.log - .artifacts/e2e-compose-prepare.log + e2e/cypress/videos + e2e/cypress/results retention-days: 30 diff --git a/.github/workflows/homebrew.yml b/.github/workflows/homebrew.yml new file mode 100644 index 000000000..f84eb7bb0 --- /dev/null +++ b/.github/workflows/homebrew.yml @@ -0,0 +1,74 @@ +name: ZITADEL Update Homebrew Formula + +on: + release: + types: [published] + +jobs: + homebrew-releaser: + runs-on: ubuntu-latest + name: homebrew-releaser + steps: + - name: Release my project to my Homebrew tap + uses: Justintime50/homebrew-releaser@v1 + with: + # The name of the homebrew tap to publish your formula to as it appears on GitHub. + # Required - strings + homebrew_owner: zitadel + homebrew_tap: homebrew-tap + + # The name of the folder in your homebrew tap where formula will be committed to. + # Default is shown - string + formula_folder: Formula + + # The Personal Access Token (saved as a repo secret) that has `repo` permissions for the repo running the action AND Homebrew tap you want to release to. + # Required - string + github_token: ${{ secrets.CR_PAT }} + + # Git author info used to commit to the homebrew tap. + # Defaults are shown - strings + commit_owner: homebrew-releaser + commit_email: homebrew-releaser@zitadel.com + + # Custom dependencies in case other formulas are needed to build the current one. + # Optional - multiline string + depends_on: | + "go" => :optional + "git" + + # Custom install command for your formula. + # Required - string + install: 'bin.install "zitadel"' + + # Custom test command for your formula so you can run `brew test`. + # Optional - string + test: 'ystem "#{bin}/zitadel -v"' + + # Allows you to set a custom download strategy. Note that you'll need + # to implement the strategy and add it to your tap repository. + # Example: https://docs.brew.sh/Formula-Cookbook#specifying-the-download-strategy-explicitly + # Optional - string + # download_strategy: CurlDownloadStrategy + + # Allows you to add a custom require_relative at the top of the formula template. + # Optional - string + # custom_require: custom_download_strategy + + # Adds URL and checksum targets for different OS and architecture pairs. Using this option assumes + # a tar archive exists on your GitHub repo with the following URL pattern (this cannot be customized): + # https://github.com/{GITHUB_OWNER}/{REPO_NAME}/releases/download/{TAG}/{REPO_NAME}-{VERSION}-{OPERATING_SYSTEM}-{ARCHITECTURE}.tar.gz' + # Darwin AMD pre-existing path example: https://github.com/justintime50/myrepo/releases/download/v1.2.0/myrepo-1.2.0-darwin-amd64.tar.gz + # Linux ARM pre-existing path example: https://github.com/justintime50/myrepo/releases/download/v1.2.0/myrepo-1.2.0-linux-arm64.tar.gz + # Optional - booleans + target_darwin_amd64: true + target_darwin_arm64: true + target_linux_amd64: true + target_linux_arm64: true + + # Skips committing the generated formula to a homebrew tap (useful for local testing). + # Default is shown - boolean + skip_commit: true + + # Logs debugging info to console. + # Default is shown - boolean + debug: true \ No newline at end of file diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml deleted file mode 100644 index 23e35ceb6..000000000 --- a/.github/workflows/integration.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Integration tests - -on: - push: - tags-ignore: - - '**' - pull_request: - branches: - - '**' - -jobs: - run: - strategy: - matrix: - db: [cockroach, postgres] - runs-on: ubuntu-20.04 - env: - DOCKER_BUILDKIT: 1 - INTEGRATION_DB_FLAVOR: ${{ matrix.db }} - ZITADEL_MASTERKEY: MasterkeyNeedsToHave32Characters - steps: - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.19 - - name: Source checkout - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - with: - driver: docker - install: true - - name: Generate gRPC definitions - run: docker build -f build/grpc/Dockerfile -t zitadel-base:local . - - name: Copy gRPC definitions - run: docker build -f build/zitadel/Dockerfile . -t zitadel-go-base --target go-copy -o . - - name: Download Go modules - run: go mod download - - name: Start ${{ matrix.db }} database - run: docker compose -f internal/integration/config/docker-compose.yaml up --wait ${INTEGRATION_DB_FLAVOR} - - name: Run zitadel init and setup - run: | - go run main.go init --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml - go run main.go setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml - - name: Run integration tests - run: go test -tags=integration -race -p 1 -v -coverprofile=profile.cov -coverpkg=./internal/...,./cmd/... ./internal/integration ./internal/api/grpc/... - - name: Publish go coverage - uses: codecov/codecov-action@v3.1.0 - with: - file: profile.cov - name: integration-tests diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..7789175d0 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,104 @@ +name: Lint + +on: + workflow_call: + inputs: + node_version: + required: true + type: string + go_version: + required: true + type: string + buf_version: + required: true + type: string + go_lint_version: + required: true + type: string + core_cache_key: + required: true + type: string + core_cache_path: + required: true + type: string + +jobs: + + lint-skip: + name: lint skip + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + steps: + - name: Lint skip + run: | + echo "Linting outside of pull requests is skipped" + + api: + name: api + runs-on: ubuntu-latest + continue-on-error: true + if: ${{ github.event_name == 'pull_request' }} + steps: + - + uses: actions/checkout@v3 + - + uses: bufbuild/buf-setup-action@v1 + with: + version: ${{ inputs.buf_version }} + github_token: ${{ secrets.GITHUB_TOKEN }} + - + name: lint + uses: bufbuild/buf-lint-action@v1 + - + uses: bufbuild/buf-breaking-action@v1 + with: + against: "https://github.com/${{ github.repository }}.git#branch=main" + + console: + if: ${{ github.event_name == 'pull_request' }} + name: console + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + uses: actions/setup-node@v3 + with: + node-version: ${{ inputs.node_version }} + cache: 'yarn' + cache-dependency-path: console/yarn.lock + - + run: cd console && yarn install + - + name: lint + run: make console_lint + + core: + name: core + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request' }} + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + uses: actions/setup-go@v4 + with: + go-version: ${{ github.event.inputs.go_version }} + - + uses: actions/cache/restore@v3 + timeout-minutes: 1 + name: restore core + with: + path: ${{ inputs.core_cache_path }} + key: ${{ inputs.core_cache_key }} + fail-on-cache-miss: true + - + uses: golangci/golangci-lint-action@v3 + with: + version: ${{ inputs.go_lint_version }} + github-token: ${{ github.token }} + only-new-issues: true + skip-pkg-cache: true + skip-build-cache: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..4f23e7bcb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,75 @@ +name: Release + +on: + workflow_call: + inputs: + semantic_version: + required: true + type: string + image: + required: true + type: string + image_name: + required: true + type: string + google_image_name: + required: true + type: string + secrets: + GCR_JSON_KEY_BASE64: + description: 'base64 endcrypted key to connect to Google' + required: true + +jobs: + version: + uses: ./.github/workflows/version.yml + with: + semantic_version: ${{ inputs.semantic_version }} + dry_run: true + + docker: + runs-on: ubuntu-22.04 + needs: [ version ] + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Login to Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Login to Google Artifact Registry + uses: docker/login-action@v2 + with: + registry: europe-docker.pkg.dev + username: _json_key_base64 + password: ${{ secrets.GCR_JSON_KEY_BASE64 }} + - + name: Publish ${{ needs.version.outputs.version }} + run: | + docker buildx imagetools create \ + --tag ${{ inputs.image_name }}:${{ needs.version.outputs.version }} \ + ${{ inputs.image }} + docker buildx imagetools create \ + --tag ${{ inputs.image_name }}:${{ needs.version.outputs.version }}-debug \ + ${{ inputs.image }}-debug + docker buildx imagetools create \ + --tag ${{ inputs.google_image_name }}:${{ needs.version.outputs.version }} \ + ${{ inputs.image }} + - + name: Publish latest + if: ${{ github.ref_name == 'main' }} + run: | + docker buildx imagetools create \ + --tag ${{ inputs.image_name }}:latest \ + ${{ inputs.image }} + docker buildx imagetools create \ + --tag ${{ inputs.image_name }}:latest-debug \ + ${{ inputs.image }}-debug diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml deleted file mode 100644 index b681d3b2d..000000000 --- a/.github/workflows/test-code.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: ZITADEL PR - -on: - pull_request: - paths-ignore: - - 'docs/**' - - 'guides/**' - - '**.md' - - 'release-channels.yaml' - -jobs: - Build-ZITADEL: - runs-on: ubuntu-20.04 - env: - DOCKER_BUILDKIT: 1 - steps: - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.19 - - name: Source checkout - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - with: - driver: docker - install: true - - name: Install GoReleaser - uses: goreleaser/goreleaser-action@v3 - with: - install-only: true - version: v1.10.3 - - name: Build and Unit Test - run: GOOS="linux" GOARCH="amd64" goreleaser build --id prod --snapshot --single-target --rm-dist --output .artifacts/zitadel/zitadel - - name: linting - uses: golangci/golangci-lint-action@v3 - with: - version: v1.52 - only-new-issues: true - skip-pkg-cache: true - - name: Publish go coverage - uses: codecov/codecov-action@v3.1.0 - with: - file: .artifacts/codecov/profile.cov - name: unit-tests - # As goreleaser doesn't build a dockerfile in snapshot mode, we have to build it here - - name: Build Docker Image - run: docker build -t zitadel:pr --file build/Dockerfile .artifacts/zitadel - - name: Run E2E Tests - run: docker compose run --service-ports e2e --browser chrome - working-directory: e2e/config/host.docker.internal - env: - ZITADEL_IMAGE: zitadel:pr - - name: Save ZITADEL Logs - if: always() - run: docker compose logs zitadel > ../../../.artifacts/e2e-compose-zitadel.log - working-directory: e2e/config/host.docker.internal - - name: Save Prepare Logs - if: always() - run: docker compose logs prepare > ../../../.artifacts/e2e-compose-prepare.log - working-directory: e2e/config/host.docker.internal - - name: Archive Test Results - if: always() - uses: actions/upload-artifact@v3 - with: - name: pull-request-tests - path: | - e2e/cypress/results - e2e/cypress/videos - e2e/cypress/screenshots - .artifacts/e2e-compose-zitadel.log - .artifacts/e2e-compose-prepare.log - retention-days: 30 diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml deleted file mode 100644 index 7bf3b222b..000000000 --- a/.github/workflows/test-docs.yml +++ /dev/null @@ -1,21 +0,0 @@ -# ATTENTION: Although this workflow doesn't do much, it is still important. -# It is complementary to the workflow in the file test-code.yml. -# It enables to exclude files for the workflow and still mark the Test job as required without having pending PRs. -# GitHub recommends this solution here: -# https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks - -name: ZITADEL PR - -on: - pull_request: - paths: - - 'docs/**' - - 'guides/**' - - '**.md' - - 'release-channels.yaml' - -jobs: - Build-ZITADEL: - runs-on: ubuntu-20.04 - steps: - - run: 'echo "No tests for docs are implemented, yet"' diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml new file mode 100644 index 000000000..f82b2ae26 --- /dev/null +++ b/.github/workflows/version.yml @@ -0,0 +1,45 @@ +name: Version + +on: + workflow_call: + inputs: + semantic_version: + required: true + type: string + dry_run: + required: true + type: boolean + outputs: + version: + value: ${{ jobs.generate.outputs.version }} + published: + value: ${{jobs.generate.outputs.published }} + +jobs: + generate: + runs-on: ubuntu-22.04 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + outputs: + version: ${{ steps.output.outputs.VERSION }} + published: ${{ steps.semantic.outputs.new_release_published }} + steps: + - + name: Source checkout + uses: actions/checkout@v3 + - + name: Semantic Release + uses: cycjimmy/semantic-release-action@v3 + id: semantic + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + dry_run: ${{ inputs.dry_run }} + semantic_version: ${{ inputs.semantic_version }} + extra_plugins: | + @semantic-release/exec@6.0.3 + - + name: output + id: output + run: + if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=" >> "$GITHUB_OUTPUT";fi diff --git a/.github/workflows/zitadel.yml b/.github/workflows/zitadel.yml deleted file mode 100644 index c5512d529..000000000 --- a/.github/workflows/zitadel.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: ZITADEL Release - -on: - push: - tags-ignore: - - "*" - workflow_dispatch: - -permissions: - contents: write - packages: write - -jobs: - Build: - runs-on: ubuntu-20.04 - env: - DOCKER_BUILDKIT: 1 - steps: - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.19 - - name: Source checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Fetch all tags - run: git fetch --force --tags - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - with: - driver: docker - install: true - - name: Tag - id: semantic - uses: cycjimmy/semantic-release-action@v2 - with: - dry_run: false - semantic_version: 19.0.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: GitHub Container Registry Login - if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - uses: tibdex/github-app-token@v1 - id: generate-token - with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} - - name: Google Artifact Registry Login - if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' - uses: docker/login-action@v2 - with: - registry: europe-docker.pkg.dev - username: _json_key_base64 - password: ${{ secrets.GCR_JSON_KEY_BASE64 }} - - uses: goreleaser/goreleaser-action@v3 - name: Publish ZITADEL - if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' - with: - distribution: goreleaser - version: v1.11.0 - args: release --timeout 50m - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GORELEASER_TOKEN_TAP: ${{ steps.generate-token.outputs.token }} - RELEASE_VERSION: ${{ steps.semantic.outputs.release-version }} # I think this line is not needed. Nevertheless, it's explicit - DISCORD_WEBHOOK_ID: "976058224484687932" - DISCORD_WEBHOOK_TOKEN: "${{ secrets.DISCORD_WEBHOOK_TOKEN }}" - - name: Publish go coverage - uses: codecov/codecov-action@v3.1.0 - with: - file: .artifacts/codecov/profile.cov - name: go-codecov - - name: Bump Chart Version - uses: peter-evans/repository-dispatch@v2 - if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/next' - with: - token: ${{ steps.generate-token.outputs.token }} - repository: zitadel/zitadel-charts - event-type: zitadel-released - client-payload: '{"semanticoutputs": "${{ steps.semantic.outputs }}"}' diff --git a/.gitignore b/.gitignore index 75d5b034f..1ed24a234 100644 --- a/.gitignore +++ b/.gitignore @@ -55,10 +55,17 @@ openapi/**/*.json /internal/api/assets/authz.go /internal/api/assets/router.go /internal/api/ui/console/static/* +!/internal/api/ui/console/static/gitkeep docs/docs/apis/auth docs/docs/apis/admin docs/docs/apis/mgmt docs/docs/apis/system +docs/docs/apis/proto +**/.sass-cache +/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css +/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css.map +zitadel +zitadel-*-* # local build/local/*.env diff --git a/.golangci.yaml b/.golangci.yaml index f6c3ab934..7768c32d6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -6,7 +6,7 @@ issues: max-same-issues: 0 run: - concurrency: 2 + concurrency: 4 timeout: 10m go: '1.19' skip-dirs: diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index bdbad1f5a..000000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,126 +0,0 @@ -project_name: zitadel - -release: - github: - owner: zitadel - name: zitadel - draft: false - # If set to auto, will mark the release as not ready for production - # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 - # If set to true, will mark the release as not ready for production. - # Default is false. - prerelease: auto - -before: - hooks: - # this file would invalidate go source caches - - sh -c "rm openapi/statik/statik.go || true" - - docker build -f build/grpc/Dockerfile -t zitadel-base:local . - - docker build -f build/zitadel/Dockerfile . -t zitadel-go-test --target go-codecov -o .artifacts/codecov - - docker build -f build/zitadel/Dockerfile . -t zitadel-go-base --target go-copy -o .artifacts/grpc/go-client - - sh -c "find pkg/grpc -name '*.pb*.go' -delete" - - sh -c "cp -r .artifacts/grpc/go-client/* ." - - docker build -f build/console/Dockerfile . -t zitadel-npm-console --target angular-export -o .artifacts/console - - sh -c "cp -r .artifacts/console/* internal/api/ui/console/static/" - -builds: - - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin - goarch: - - amd64 - - arm64 - ldflags: -s -w -X github.com/zitadel/zitadel/cmd/build.version={{.Version}} -X github.com/zitadel/zitadel/cmd/build.commit={{.Commit}} -X github.com/zitadel/zitadel/cmd/build.date={{.Date}} - -dist: .artifacts/goreleaser - -dockers: - - image_templates: - - ghcr.io/zitadel/zitadel:{{ .Tag }}-amd64 - - europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel:{{ .Tag }}-amd64 - goarch: amd64 - use: buildx - dockerfile: build/Dockerfile - build_flag_templates: - - "--platform=linux/amd64" - - image_templates: - - ghcr.io/zitadel/zitadel:{{ .Tag }}-arm64 - - ghcr.io/zitadel/zitadel:{{ .ShortCommit }}-arm64 - goarch: arm64 - use: buildx - dockerfile: build/Dockerfile - build_flag_templates: - - "--platform=linux/arm64" - -docker_manifests: - - id: zitadel-latest - name_template: ghcr.io/zitadel/zitadel:latest - image_templates: - - ghcr.io/zitadel/zitadel:{{ .Tag }}-amd64 - - ghcr.io/zitadel/zitadel:{{ .Tag }}-arm64 - # Skips can and shall be set for individual manifests same as in dockers - skip_push: auto - - id: zitadel-Tag - name_template: ghcr.io/zitadel/zitadel:{{ .Tag }} - image_templates: - - ghcr.io/zitadel/zitadel:{{ .Tag }}-amd64 - - ghcr.io/zitadel/zitadel:{{ .Tag }}-arm64 - -archives: - - name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" - replacements: - darwin: Darwin - linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 - format_overrides: - - goos: windows - format: zip - files: - - README.md - - LICENSE - -gomod: - proxy: false - -checksum: - name_template: "checksums.txt" - -changelog: - sort: asc - filters: - exclude: - - "^docs:" - - "^test:" - -brews: - - tap: - owner: zitadel - name: homebrew-tap - token: "{{ .Env.GORELEASER_TOKEN_TAP }}" - folder: Formula - goarm: "7" - homepage: https://zitadel.com - description: Open source identity solution built for the container and cloud era - license: Apache 2.0 - test: | - system "#{bin}/zitadel -v" - dependencies: - - name: go - type: optional - - name: git - install: |- - bin.install "zitadel" - # If set to auto, the release will not be uploaded to the homebrew tap - # in case there is an indicator for prerelease in the tag e.g. v1.0.0-rc1 - # Default is false. - skip_upload: auto - -announce: - discord: - enabled: true - message_template: "ZITADEL {{ .Tag }} is ready! Check the notes: https://github.com/zitadel/zitadel/releases/tag/{{ .Tag }}" diff --git a/.releaserc.js b/.releaserc.js index 2103f3f3d..920186b88 100644 --- a/.releaserc.js +++ b/.releaserc.js @@ -1,10 +1,12 @@ module.exports = { - branches: [ - { name: 'main' }, - { name: 'next' }, - { name: 'rc', prerelease: true }, - ], - plugins: [ - "@semantic-release/commit-analyzer" - ] + branches: [ + { name: "main" }, + { name: "next" }, + { name: "rc", prerelease: true }, + ], + plugins: [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/github" + ], }; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06be1797a..5884c559b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,26 +34,30 @@ Follow [@zitadel](https://twitter.com/zitadel) on twitter We strongly recommend to [talk to us](https://zitadel.com/contact) before you start contributing to streamline our and your work. -We accept contributions through pull requests. You need a github account for that. If you are unfamiliar with git have a look at Github's documentation on [creating forks](https://help.github.com/articles/fork-a-repo) and [creating pull requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). Please draft the pull request as soon as possible. Go through the following checklist before you submit the final pull request: +We accept contributions through pull requests. +You need a github account for that. +If you are unfamiliar with git have a look at Github's documentation on [creating forks](https://help.github.com/articles/fork-a-repo) and [creating pull requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). +Please draft the pull request as soon as possible. +Go through the following checklist before you submit the final pull request: ### Submit a pull request (PR) 1. [Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) the [zitadel/zitadel](https://github.com/zitadel/zitadel) repository on GitHub 2. On your fork, commit your changes to a new branch - `git checkout -b my-fix-branch main` + `git checkout -b my-fix-branch main` 3. Make your changes following the [guidelines](#contribute) in this guide. Make sure that all tests pass. 4. Commit the changes on the new branch - `git commit --all` + `git commit --all` 5. [Merge](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging) the latest commit of the `main`-branch 6. Push the changes to your branch on Github - `git push origin my-fix-branch` + `git push origin my-fix-branch` 7. Use [Semantic Release commit messages](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type) to simplify creation of release notes. In the title of the pull request [correct tagging](#commit-messages) is required and will be requested by the reviewers. @@ -61,7 +65,8 @@ We accept contributions through pull requests. You need a github account for tha ### Review a pull request -The reviewers will provide you feedback and approve your changes as soon as they are satisfied. If we ask you for changes in the code, you can follow the [GitHub Guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request) to incorporate feedback in your pull request. +The reviewers will provide you feedback and approve your changes as soon as they are satisfied. +If we ask you for changes in the code, you can follow the [GitHub Guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request) to incorporate feedback in your pull request. @@ -88,6 +93,16 @@ This is optional to indicate which component is affected. In doubt, leave blank Provide a brief description of the change. +### Quality assurance + +Please make sure you cover your changes with tests before marking a Pull Request as ready for review: + +- [ ] Integration tests against the gRPC server ensure that one or multiple API calls that belong together return the expected results. +- [ ] Integration tests against the gRPC server ensure that probable good and bad read and write permissions are tested. +- [ ] Integration tests against the gRPC server ensure that the API is easily usable despite eventual consistency. +- [ ] Integration tests against the gRPC server ensure that all probable login and registration flows are covered." +- [ ] Integration tests ensure that certain commands send expected notifications. + ## Contribute The code consists of the following parts: @@ -111,7 +126,7 @@ We add the label "good first issue" for problems we think are a good starting po By executing the commands from this section, you run everything you need to develop the ZITADEL backend locally. Using [Docker Compose](https://docs.docker.com/compose/), you run a [CockroachDB](https://www.cockroachlabs.com/docs/stable/start-a-local-cluster-in-docker-mac.html) on your local machine. -With [goreleaser](https://opencollective.com/goreleaser), you build a debuggable ZITADEL binary and run it using [delve](https://github.com/go-delve/delve). +With [make](https://www.gnu.org/software/make/), you build a debuggable ZITADEL binary and run it using [delve](https://github.com/go-delve/delve). Then, you test your changes via the console your binary is serving at http://localhost:8080 and by verifying the database. Once you are happy with your changes, you run end-to-end tests and tear everything down. @@ -120,8 +135,7 @@ ZITADEL uses [golangci-lint](https://golangci-lint.run) for code quality checks. The commands in this section are tested against the following software versions: - [Docker version 20.10.17](https://docs.docker.com/engine/install/) -- [Goreleaser version v1.8.3](https://goreleaser.com/install/) -- [Go version 1.19](https://go.dev/doc/install) +- [Go version 1.20](https://go.dev/doc/install) - [Delve 1.9.1](https://github.com/go-delve/delve/tree/v1.9.1/Documentation/installation) Make some changes to the source code, then run the database locally. @@ -134,16 +148,15 @@ docker compose --file ./e2e/docker-compose.yaml up --detach db Build the binary. This takes some minutes, but you can speed up rebuilds. ```bash -# You just need goreleasers build part (--snapshot) and you just need to target your current platform (--single-target) -goreleaser build --id dev --snapshot --single-target --rm-dist --output .artifacts/zitadel/zitadel +make compile ``` > Note: With this command, several steps are executed. > For speeding up rebuilds, you can reexecute only specific steps you think are necessary based on your changes. -> Generating gRPC stubs: `DOCKER_BUILDKIT=1 docker build -f build/zitadel/Dockerfile . --target go-copy -o .` -> Running unit tests: `DOCKER_BUILDKIT=1 docker build -f build/zitadel/Dockerfile . --target go-codecov` -> Generating the console: `DOCKER_BUILDKIT=1 docker build -f build/console/Dockerfile . --target angular-export -o internal/api/ui/console/static/` -> Build the binary: `goreleaser build --id dev --snapshot --single-target --rm-dist --output .artifacts/zitadel/zitadel --skip-before` +> Generating gRPC stubs: `make core_api` +> Running unit tests: `make core_unit_test` +> Generating the console: `make console_build console_move` +> Build the binary: `make compile` You can now run and debug the binary in .artifacts/zitadel/zitadel using your favourite IDE, for example GoLand. You can test if ZITADEL does what you expect by using the UI at http://localhost:8080/ui/console. @@ -151,19 +164,20 @@ Also, you can verify the data by running `cockroach sql --database zitadel --ins As soon as you are ready to battle test your changes, run the end-to-end tests. -#### Running the tests with docker +#### Running the tests -Running the tests with docker doesn't require you to take care of other dependencies than docker and goreleaser. +Running the tests with docker doesn't require you to take care of other dependencies than docker and make. ```bash # Build the production binary (unit tests are executed, too) -goreleaser build --id prod --snapshot --single-target --rm-dist --output .artifacts/zitadel/zitadel +make core_build console_build +GOOS=linux make compile_pipeline # Pack the binary into a docker image -DOCKER_BUILDKIT=1 docker build --file build/Dockerfile .artifacts/zitadel -t zitadel:local +DOCKER_BUILDKIT=1 docker build --file build/Dockerfile . -t zitadel:local # If you made changes in the e2e directory, make sure you reformat the files -(cd ./e2e && npm run lint:fix) +make console_lint # Run the tests ZITADEL_IMAGE=zitadel:local docker compose --file ./e2e/config/host.docker.internal/docker-compose.yaml run --service-ports e2e @@ -206,9 +220,7 @@ In order to run the integrations tests for the gRPC API, PostgreSQL and Cockroac ```bash export INTEGRATION_DB_FLAVOR="cockroach" ZITADEL_MASTERKEY="MasterkeyNeedsToHave32Characters" docker compose -f internal/integration/config/docker-compose.yaml up --wait ${INTEGRATION_DB_FLAVOR} -go run main.go init --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml -go run main.go setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml -go test -count 1 -tags=integration -race -p 1 ./internal/integration ./internal/api/grpc/... +make core_integration_test docker compose -f internal/integration/config/docker-compose.yaml down ``` @@ -221,7 +233,7 @@ Using [Docker Compose](https://docs.docker.com/compose/), you run [CockroachDB]( You use the ZITADEL container as backend for your console. The console is run in your [Node](https://nodejs.org/en/about/) environment using [a local development server for Angular](https://angular.io/cli/serve#ng-serve), so you have fast feedback about your changes. -We use angular-eslint/Prettier for linting/formatting, so please run `npm run lint:fix` before committing. (VSCode users, check out [this ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [this Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to fix lint and formatting issues in development) +We use angular-eslint/Prettier for linting/formatting, so please run `yarn lint:fix` before committing. (VSCode users, check out [this ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [this Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to fix lint and formatting issues in development) Once you are happy with your changes, you run end-to-end tests and tear everything down. @@ -269,16 +281,16 @@ You can run the local console development server now. ```bash # Install npm dependencies -npm install +yarn install # Generate source files from Protos -npm run generate +yarn generate # Start the server -npm start +yarn start # If you don't want to develop against http://localhost:8080, you can use another environment -ENVIRONMENT_JSON_URL=https://my-cloud-instance-abcdef.zitadel.cloud/ui/console/assets/environment.json npm start +ENVIRONMENT_JSON_URL=https://my-cloud-instance-abcdef.zitadel.cloud/ui/console/assets/environment.json yarn start ``` Navigate to http://localhost:4200/. @@ -288,7 +300,7 @@ Open another shell. ```bash # Reformat your console code -npm run lint:fix +yarn lint:fix # Change to the e2e directory cd .. && cd e2e/ @@ -335,13 +347,13 @@ Please refer to the [README](./docs/README.md) for more information and local te ### Style guide - **Code with variables**: Make sure that code snippets can be used by setting environment variables, instead of manually replacing a placeholder. -- **Embedded files**: When embedding mdx files, make sure the template ist prefixed by "_" (lowdash). The content will be rendered inside the parent page, but is not accessible individually (eg, by search). +- **Embedded files**: When embedding mdx files, make sure the template ist prefixed by "\_" (lowdash). The content will be rendered inside the parent page, but is not accessible individually (eg, by search). - **Don't repeat yourself**: When using the same content in multiple places, save and manage the content as separate file and make use of embedded files to import it into other docs pages. - **Embedded code**: You can embed code snippets from a repository. See the [plugin](https://github.com/saucelabs/docusaurus-theme-github-codeblock#usage) for usage. Following the [Google style guide](https://developers.google.com/style) is highly recommended. Its clear and concise guidelines ensure consistency and effective communication within the wider developer community. -The style guide covers a lot of material, so their [highlights](https://developers.google.com/style/highlights) page provides an overview of its most important points. Some of the points stated in the highlights that we care about most are given below: +The style guide covers a lot of material, so their [highlights](https://developers.google.com/style/highlights) page provides an overview of its most important points. Some of the points stated in the highlights that we care about most are given below: - Be conversational and friendly without being frivolous. - Use sentence case for document titles and section headings. @@ -414,7 +426,6 @@ Priority shows you the priority the ZITADEL team has given this issue. In genera - **🏕 Medium**: After all the high issues are done these will be next. - **🏝 Low**: This is low in priority and will probably not be implemented in the next time or just if someone has some time in between. - #### Complexity This should give you an indication how complex the issue is. It's not about the hours or effort it takes. @@ -448,4 +459,3 @@ The language shows you in which programming language the affected part is writte - **lang: angular** - **lang: go** - **lang: javascript** - diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..dcb0e2b1f --- /dev/null +++ b/Makefile @@ -0,0 +1,112 @@ +go_bin := "$$(go env GOPATH)/bin" +gen_authopt_path := "$(go_bin)/protoc-gen-authoption" +gen_zitadel_path := "$(go_bin)/protoc-gen-zitadel" + +now := $(shell date --rfc-3339=seconds | sed 's/ /T/') +VERSION ?= development +COMMIT_SHA ?= $(shell git rev-parse HEAD) + +.PHONY: compile +compile: core_build console_build compile_pipeline + +.PHONY: compile_pipeline +compile_pipeline: console_move + CGO_ENABLED=0 go build -o zitadel -v -ldflags="-s -w -X 'github.com/zitadel/zitadel/cmd/build.commit=$(COMMIT_SHA)' -X 'github.com/zitadel/zitadel/cmd/build.date=$(now)' -X 'github.com/zitadel/zitadel/cmd/build.version=$(VERSION)' " + chmod +x zitadel + +.PHONY: core_dependencies +core_dependencies: + go mod download + +.PHONY: core_static +core_static: + go install github.com/rakyll/statik@v0.1.7 + go generate internal/api/ui/login/statik/generate.go + go generate internal/api/ui/login/static/resources/generate.go + go generate internal/notification/statik/generate.go + go generate internal/statik/generate.go + +.PHONY: core_assets +core_assets: + mkdir -p docs/apis/assets + go run internal/api/assets/generator/asset_generator.go -directory=internal/api/assets/generator/ -assets=docs/apis/assets/assets.md + +.PHONY: core_api_generator +core_api_generator: +ifeq (,$(wildcard $(gen_authopt_path))) + go install internal/protoc/protoc-gen-authoption/main.go \ + && mv $$(go env GOPATH)/bin/main $(gen_authopt_path) +endif +ifeq (,$(wildcard $(gen_zitadel_path))) + go install internal/protoc/protoc-gen-zitadel/main.go \ + && mv $$(go env GOPATH)/bin/main $(gen_zitadel_path) +endif + +.PHONY: core_grpc_dependencies +core_grpc_dependencies: + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.30 + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3 + go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.15.2 + go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.15.2 + go install github.com/envoyproxy/protoc-gen-validate@v0.10.1 + +.PHONY: core_api +core_api: core_api_generator core_grpc_dependencies + buf generate + mkdir -p pkg/grpc + cp -r .artifacts/grpc/github.com/zitadel/zitadel/pkg/grpc/* pkg/grpc/ + mkdir -p openapi/v2/zitadel + cp -r .artifacts/grpc/zitadel/ openapi/v2/zitadel + +.PHONY: core_build +core_build: core_dependencies core_api core_static core_assets + +.PHONY: console_move +console_move: + cp -r console/dist/console/* internal/api/ui/console/static + +.PHONY: console_dependencies +console_dependencies: + cd console && \ + yarn install --immutable + +.PHONY: console_client +console_client: + cd console && \ + yarn generate + +.PHONY: console_build +console_build: console_dependencies console_client + cd console && \ + yarn build + +.PHONY: clean +clean: + $(RM) .artifacts/grpc + $(RM) $(gen_authopt_path) + $(RM) $(gen_zitadel_path) + +.PHONY: core_unit_test +core_unit_test: + go test -race -coverprofile=profile.cov ./... + +.PHONY: core_integration_test +core_integration_test: + go build -o zitadel main.go + ./zitadel init --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml + ./zitadel setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml + $(RM) zitadel + go test -tags=integration -race -p 1 -v -coverprofile=profile.cov -coverpkg=./internal/...,./cmd/... ./internal/integration ./internal/api/grpc/... ./internal/notification/handlers/... ./internal/api/oidc/... + +.PHONY: console_lint +console_lint: + cd console && \ + yarn lint + +.PHONE: core_lint +core_lint: + golangci-lint run \ + --timeout 10m \ + --config ./.golangci.yaml \ + --out-format=github-actions \ + --concurrency=$$(getconf _NPROCESSORS_ONLN) \ No newline at end of file diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 000000000..858a1e640 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,21 @@ +version: v1 +plugins: + - plugin: go + out: .artifacts/grpc + - plugin: go-grpc + out: .artifacts/grpc + - plugin: grpc-gateway + out: .artifacts/grpc + opt: + - allow_delete_body=true + - plugin: openapiv2 + out: .artifacts/grpc + opt: + - allow_delete_body=true + - plugin: validate + out: .artifacts/grpc + opt: lang=go + - plugin: authoption + out: .artifacts/grpc + - plugin: zitadel + out: .artifacts/grpc diff --git a/build/Dockerfile b/build/Dockerfile index 7f99893b6..4e984fe8e 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,20 +1,32 @@ -####################### -## Final Production Image -####################### -FROM alpine:3 as artifact +FROM --platform=$TARGETPLATFORM debian:latest as artifact +ENV ZITADEL_ARGS= +ARG TARGETPLATFORM + +RUN apt-get update && apt-get install ca-certificates -y + +COPY build/entrypoint.sh /app/entrypoint.sh COPY zitadel /app/zitadel -RUN adduser -D zitadel && \ + +RUN useradd -s "" --home / zitadel && \ chown zitadel /app/zitadel && \ - chmod +x /app/zitadel + chmod +x /app/zitadel && \ + chown zitadel /app/entrypoint.sh && \ + chmod +x /app/entrypoint.sh + +WORKDIR /app +ENV PATH="/app:${PATH}" + +USER zitadel +ENTRYPOINT ["/app/entrypoint.sh"] + +FROM --platform=$TARGETPLATFORM scratch as final +ARG TARGETPLATFORM -####################### -## Scratch Image -####################### -FROM scratch as final COPY --from=artifact /etc/passwd /etc/passwd COPY --from=artifact /etc/ssl/certs /etc/ssl/certs -COPY --from=artifact /app / -USER zitadel -HEALTHCHECK NONE -ENTRYPOINT ["/zitadel"] +COPY --from=artifact /app/zitadel /app/zitadel +HEALTHCHECK NONE + +USER zitadel +ENTRYPOINT ["/app/zitadel"] \ No newline at end of file diff --git a/build/console/Dockerfile b/build/console/Dockerfile deleted file mode 100644 index 9249ce368..000000000 --- a/build/console/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -ARG NODE_VERSION=18 - -####################### -## With this step we prepare all node_modules, this helps caching the build -## Speed up this step by mounting your local node_modules directory -## We also copy and generate the source code -####################### -FROM node:${NODE_VERSION} as npm-base -WORKDIR /console - -# Dependencies -COPY console/package.json console/package-lock.json ./ -RUN npm ci - -# Sources -COPY console . -COPY proto/ /proto/ - -####################### -## angular lint workspace and prod build -####################### -FROM npm-base as angular-build -RUN npm run lint -RUN npm run build - -####################### -## Only Copy Assets -####################### -FROM scratch as angular-export -COPY --from=angular-build /console/dist/console . diff --git a/build/entrypoint.sh b/build/entrypoint.sh new file mode 100755 index 000000000..465596daf --- /dev/null +++ b/build/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +case $@ in + sh*) + ${@:3} + ;; + bash*) + ${@:5} + ;; + *) + if [[ ! -z "$@" ]] + then + ZITADEL_ARGS="$@" + fi + /app/zitadel ${ZITADEL_ARGS} + ;; +esac diff --git a/build/grpc/Dockerfile b/build/grpc/Dockerfile deleted file mode 100644 index d6b86dd01..000000000 --- a/build/grpc/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -#ARG BUILDARCH=x86_64 - -####################### -## These steps set platform / arch type specific variables -####################### -FROM alpine:3 AS arm64-base -ENV PROTOC_ARCH aarch_64 - -FROM alpine:3 AS amd64-base -ENV PROTOC_ARCH x86_64 - -####################### -## This step sets up the folder structure, -## initalices go mods, -## downloads the protofiles, -## protoc and protoc-gen-grpc-web for later use -####################### -FROM ${BUILDARCH}-base -ARG PROTOC_VERSION=22.3 -ARG PROTOC_ZIP=protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip -ARG GRPC_WEB_VERSION=1.3.0 -ARG GATEWAY_VERSION=2.15.2 -ARG VALIDATOR_VERSION=0.10.1 -# no arm specific version available and x86 works fine at the moment: -ARG GRPC_WEB=protoc-gen-grpc-web-${GRPC_WEB_VERSION}-linux-x86_64 - -RUN apk add tar curl -WORKDIR /proto - -#protoc -RUN apk add tar curl \ - && curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/$PROTOC_ZIP \ - && unzip -o $PROTOC_ZIP -d /usr/local bin/protoc \ - && unzip -o $PROTOC_ZIP -d /proto include/* \ - && rm -f $PROTOC_ZIP \ - && curl -OL https://github.com/grpc/grpc-web/releases/download/${GRPC_WEB_VERSION}/${GRPC_WEB} \ - && mv ${GRPC_WEB} /usr/local/bin/protoc-gen-grpc-web \ - && chmod +x /usr/local/bin/protoc-gen-grpc-web \ - && curl https://raw.githubusercontent.com/envoyproxy/protoc-gen-validate/v${VALIDATOR_VERSION}/validate/validate.proto --create-dirs -o include/validate/validate.proto \ - && curl https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v${GATEWAY_VERSION}/protoc-gen-openapiv2/options/annotations.proto --create-dirs -o include/protoc-gen-openapiv2/options/annotations.proto \ - && curl https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v${GATEWAY_VERSION}/protoc-gen-openapiv2/options/openapiv2.proto --create-dirs -o include/protoc-gen-openapiv2/options/openapiv2.proto \ - && curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/annotations.proto --create-dirs -o include/google/api/annotations.proto \ - && curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto --create-dirs -o include/google/api/http.proto \ - && curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/field_behavior.proto --create-dirs -o include/google/api/field_behavior.proto - -#zitadel protos -COPY proto/ include/. diff --git a/build/workflow.Dockerfile b/build/workflow.Dockerfile new file mode 100644 index 000000000..c9fb7e6c2 --- /dev/null +++ b/build/workflow.Dockerfile @@ -0,0 +1,302 @@ +# ############################################################################## +# core +# ############################################################################## + +# ####################################### +# download dependencies +# ####################################### +FROM golang:buster AS core-deps + +WORKDIR /go/src/github.com/zitadel/zitadel + +COPY go.mod . +COPY go.sum . + +RUN go mod download + +# ####################################### +# compile custom protoc plugins +# ####################################### +FROM golang:buster AS core-api-generator + +WORKDIR /go/src/github.com/zitadel/zitadel + +COPY go.mod . +COPY go.sum . +COPY internal/protoc internal/protoc +COPY pkg/grpc/protoc/v2 pkg/grpc/protoc/v2 + +RUN go install internal/protoc/protoc-gen-authoption/main.go \ + && mv $(go env GOPATH)/bin/main $(go env GOPATH)/bin/protoc-gen-authoption \ + && go install internal/protoc/protoc-gen-zitadel/main.go \ + && mv $(go env GOPATH)/bin/main $(go env GOPATH)/bin/protoc-gen-zitadel + +# ####################################### +# build backend stub +# ####################################### +FROM golang:buster AS core-api + +WORKDIR /go/src/github.com/zitadel/zitadel + +COPY go.mod . +COPY go.sum . +COPY proto proto +COPY buf.*.yaml . +COPY Makefile Makefile +COPY --from=core-api-generator /go/bin /usr/local/bin + +RUN make grpc + +# ####################################### +# generate code for login ui +# ####################################### +FROM golang:buster AS core-login + +WORKDIR /go/src/github.com/zitadel/zitadel + +COPY Makefile Makefile +COPY internal/api/ui/login/static internal/api/ui/login/static +COPY internal/api/ui/login/statik internal/api/ui/login/statik +COPY internal/notification/static internal/notification/static +COPY internal/notification/statik internal/notification/statik +COPY internal/static internal/static +COPY internal/statik internal/statik + +RUN make static + +# ####################################### +# generate code for assets +# ####################################### +FROM golang:buster AS core-assets +WORKDIR /go/src/github.com/zitadel/zitadel + +COPY go.mod . +COPY go.sum . +COPY Makefile Makefile +COPY internal/api/assets/generator internal/api/assets/generator +COPY internal/config internal/config +COPY internal/errors internal/errors +COPY --from=core-api /go/src/github.com/zitadel/zitadel/openapi/v2 openapi/v2 + +RUN make assets + +# ####################################### +# Gather all core files +# ####################################### +FROM core-deps AS core-gathered + +COPY cmd cmd +COPY internal internal +COPY pkg pkg +COPY proto proto +COPY openapi openapi +COPY statik statik +COPY main.go main.go +COPY --from=core-api /go/src/github.com/zitadel/zitadel . +COPY --from=core-login /go/src/github.com/zitadel/zitadel . +COPY --from=core-assets /go/src/github.com/zitadel/zitadel/internal ./internal + +# ############################################################################## +# build console +# ############################################################################## + +# ####################################### +# download console dependencies +# ####################################### +FROM node:18-buster AS console-deps + +WORKDIR /zitadel/console + +COPY console/package.json . +COPY console/yarn.lock . + +RUN yarn install --frozen-lockfile + +# ####################################### +# generate console client +# ####################################### +FROM node:18-buster AS console-client + +WORKDIR /zitadel/console + +# install buf +COPY --from=bufbuild/buf:latest /usr/local/bin/* /usr/local/bin/ +ENV PATH="/usr/local/bin:${PATH}" + +COPY console/package.json . +COPY console/buf.*.yaml . +COPY proto ../proto + +RUN yarn generate + +# ####################################### +# Gather all console files +# ####################################### +FROM console-deps as console-gathered + +COPY --from=console-client /zitadel/console/src/app/proto/generated src/app/proto/generated + +COPY console/src src +COPY console/angular.json . +COPY console/ngsw-config.json . +COPY console/tsconfig* . + +# ####################################### +# Build console +# ####################################### +FROM console-gathered AS console +RUN yarn build + +# ############################################################################## +# build the executable +# ############################################################################## + +# ####################################### +# build executable +# ####################################### +FROM core-gathered AS compile + +ARG GOOS +ARG GOARCH + +COPY --from=console /zitadel/console/dist/console internal/api/ui/console/static/ + +RUN go build -o zitadel -ldflags="-s -w -race" \ + && chmod +x zitadel + +ENTRYPOINT [ "./zitadel" ] + +# ####################################### +# copy executable +# ####################################### +FROM scratch AS copy-executable +ARG GOOS +ARG GOARCH + +COPY --from=compile /go/src/github.com/zitadel/zitadel/zitadel /.artifacts/zitadel + +# ############################################################################## +# tests +# ############################################################################## +FROM ubuntu/postgres:latest AS test-core-base + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc \ + make \ + ca-certificates \ + gcc \ + && \ + update-ca-certificates; \ + rm -rf /var/lib/apt/lists/* + +# install go +COPY --from=golang:latest /usr/local/go/ /usr/local/go/ +ENV PATH="/go/bin:/usr/local/go/bin:${PATH}" + +WORKDIR /go/src/github.com/zitadel/zitadel + +# default vars +ENV DB_FLAVOR=postgres +ENV POSTGRES_USER=zitadel +ENV POSTGRES_DB=zitadel +ENV POSTGRES_PASSWORD=postgres +ENV POSTGRES_HOST_AUTH_METHOD=trust + +ENV PGUSER=zitadel +ENV PGDATABASE=zitadel +ENV PGPASSWORD=postgres + +ENV CGO_ENABLED=1 + +# copy zitadel files +COPY --from=core-deps /go/pkg/mod /root/go/pkg/mod +COPY --from=core-gathered /go/src/github.com/zitadel/zitadel . + +# ####################################### +# unit test core +# ####################################### +FROM test-core-base AS test-core-unit +RUN go test -race -v -coverprofile=profile.cov ./... + +# ####################################### +# coverage output +# ####################################### +FROM scratch AS coverage-core-unit +COPY --from=test-core-unit /go/src/github.com/zitadel/zitadel/profile.cov /coverage/ + +# ####################################### +# integration test core +# ####################################### +FROM test-core-base AS test-core-integration +ENV DB_FLAVOR=cockroach + +# install cockroach +COPY --from=cockroachdb/cockroach:latest /cockroach/cockroach /usr/local/bin/ +ENV COCKROACH_BINARY=/cockroach/cockroach + +ENV ZITADEL_MASTERKEY=MasterkeyNeedsToHave32Characters + +COPY build/core-integration-test.sh /usr/local/bin/run-tests.sh +RUN chmod +x /usr/local/bin/run-tests.sh + +RUN run-tests.sh + +# ####################################### +# coverage output +# ####################################### +FROM scratch AS coverage-core-integration +COPY --from=test-core-integration /go/src/github.com/zitadel/zitadel/profile.cov /coverage/ + +# ############################################################################## +# linting +# ############################################################################## + +# ####################################### +# api +# ####################################### +FROM bufbuild/buf:latest AS lint-api + +COPY proto proto +COPY buf.*.yaml . + +RUN buf lint + +# ####################################### +# console +# ####################################### +FROM console-gathered AS lint-console + +COPY console/.eslintrc.js . +COPY console/.prettier* . +RUN yarn lint + +# ####################################### +# core +# ####################################### +FROM golangci/golangci-lint:latest AS lint-core +ARG LINT_EXIT_CODE=1 + +WORKDIR /go/src/github.com/zitadel/zitadel + +COPY .golangci.yaml . +COPY .git/ .git/ +COPY --from=core-deps /go/pkg/mod /go/pkg/mod +COPY --from=core-gathered /go/src/github.com/zitadel/zitadel . + +RUN git fetch https://github.com/zitadel/zitadel main:main + +RUN golangci-lint run \ + --timeout 10m \ + --config ./.golangci.yaml \ + --out-format=github-actions:report,colored-line-number \ + --issues-exit-code=${LINT_EXIT_CODE} \ + --concurrency=$(getconf _NPROCESSORS_ONLN) + +# ####################################### +# report output +# ####################################### +FROM scratch AS lint-core-report +COPY --from=lint-core /go/src/github.com/zitadel/zitadel/report . \ No newline at end of file diff --git a/build/zitadel/Dockerfile b/build/zitadel/Dockerfile deleted file mode 100644 index 7c0f7bdca..000000000 --- a/build/zitadel/Dockerfile +++ /dev/null @@ -1,107 +0,0 @@ -ARG GO_VERSION=1.19 - -####################### -## Go dependencies -## Speed up this step by mounting your local go mod pkg directory -####################### -FROM golang:${GO_VERSION} as go-dep -WORKDIR /go/src/github.com/zitadel/zitadel - -#download modules -COPY go.mod ./ -COPY go.sum ./ -RUN go mod download - -# install tools -COPY tools ./tools -RUN ./tools/install.sh - -####################### -## generates static files -####################### -FROM go-dep AS go-static -COPY internal/api/ui/login/static internal/api/ui/login/static -COPY internal/api/ui/login/statik internal/api/ui/login/statik -COPY internal/notification/static internal/notification/static -COPY internal/notification/statik internal/notification/statik -COPY internal/static internal/static -COPY internal/statik internal/statik - -RUN go generate internal/api/ui/login/statik/generate.go \ - && go generate internal/api/ui/login/static/generate.go \ - && go generate internal/notification/statik/generate.go \ - && go generate internal/statik/generate.go - -####################### -## generates grpc stub -####################### -FROM go-static AS go-stub -COPY --from=zitadel-base:local /proto /proto -COPY --from=zitadel-base:local /usr/local/bin /usr/local/bin/. - -COPY build/zitadel/generate-grpc.sh build/zitadel/generate-grpc.sh -COPY internal/protoc internal/protoc -COPY openapi/statik openapi/statik -COPY internal/api/assets/generator internal/api/assets/generator -COPY internal/config internal/config -COPY internal/errors internal/errors - -RUN build/zitadel/generate-grpc.sh && \ - go generate openapi/statik/generate.go && \ - mkdir -p docs/apis/assets/ && \ - go run internal/api/assets/generator/asset_generator.go -directory=internal/api/assets/generator/ -assets=docs/apis/assets/assets.md - -####################### -## Go base build -####################### -FROM go-stub as go-base -# copy remaining zitadel files -COPY cmd cmd -COPY internal internal -COPY pkg pkg -COPY openapi openapi - -####################### -## copy for local dev -####################### -FROM scratch as go-copy -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/api/ui/login/statik/statik.go internal/api/ui/login/statik/statik.go -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/notification/statik/statik.go internal/notification/statik/statik.go -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/statik/statik.go internal/statik/statik.go -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/openapi/statik/statik.go openapi/statik/statik.go - -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/pkg/grpc pkg/grpc -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/openapi/v2/zitadel openapi/v2/zitadel -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/openapi/statik/statik.go openapi/statik/statik.go -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/protoc/protoc-gen-authoption/authoption/options.pb.go internal/protoc/protoc-gen-authoption/authoption/options.pb.go -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/docs/apis/proto docs/docs/apis/proto -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/docs/apis/assets docs/docs/apis/assets - -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/api/assets/authz.go ./internal/api/assets/authz.go -COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/api/assets/router.go ./internal/api/assets/router.go - -####################### -## Go test -####################### -FROM go-base as go-test - -ARG COCKROACH_BINARY=/usr/local/bin/cockroach -ARG COCKROACH_VERSION=v22.2.2 -RUN apt install openssl tzdata tar - -# cockroach binary used to backup database -RUN mkdir /usr/local/lib/cockroach -RUN wget -qO- https://binaries.cockroachdb.com/cockroach-${COCKROACH_VERSION}.linux-amd64.tgz \ - | tar xvz && cp -i cockroach-${COCKROACH_VERSION}.linux-amd64/cockroach /usr/local/bin/ -RUN rm -r cockroach-${COCKROACH_VERSION}.linux-amd64 - -# Migrations for cockroach-secure -RUN go install github.com/rakyll/statik \ - && go test -race -v -coverprofile=profile.cov $(go list ./... | grep -v /operator/) - -####################### -## Go test results -####################### -FROM scratch as go-codecov -COPY --from=go-test /go/src/github.com/zitadel/zitadel/profile.cov profile.cov - diff --git a/build/zitadel/generate-grpc.sh b/build/zitadel/generate-grpc.sh index 865952fb6..e69de29bb 100755 --- a/build/zitadel/generate-grpc.sh +++ b/build/zitadel/generate-grpc.sh @@ -1,111 +0,0 @@ -#!/bin/sh - -set -eux - -echo "Generate grpc" - -OPENAPI_PATH=${GOPATH}/src/github.com/zitadel/zitadel/openapi/v2 -ZITADEL_PATH=${GOPATH}/src/github.com/zitadel/zitadel -GRPC_PATH=${ZITADEL_PATH}/pkg/grpc -PROTO_PATH=/proto/include/zitadel -DOCS_PATH=${ZITADEL_PATH}/docs/apis/proto - -# generate go stub and grpc code for all files -protoc \ - -I=/proto/include/ \ - --go_out $GOPATH/src \ - --go-grpc_out $GOPATH/src \ - --validate_out=lang=go:${GOPATH}/src \ - $(find ${PROTO_PATH} -iname *.proto) - -# install authoption and zitadel proto compiler -go install ${ZITADEL_PATH}/internal/protoc/protoc-gen-auth -go install ${ZITADEL_PATH}/internal/protoc/protoc-gen-zitadel - -# output folder for openapi v2 -mkdir -p ${OPENAPI_PATH} -mkdir -p ${DOCS_PATH} - -# generate additional output - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --auth_out ${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/system.proto - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --auth_out ${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/admin.proto - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --grpc-gateway_opt allow_delete_body=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --openapiv2_opt allow_delete_body=true \ - --auth_out ${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/management.proto - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --grpc-gateway_opt allow_delete_body=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --openapiv2_opt allow_delete_body=true \ - --auth_out=${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/auth.proto - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --grpc-gateway_opt allow_delete_body=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --openapiv2_opt allow_delete_body=true \ - --zitadel_out=${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/user/v2alpha/user_service.proto - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --grpc-gateway_opt allow_delete_body=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --openapiv2_opt allow_delete_body=true \ - --zitadel_out=${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/session/v2alpha/session_service.proto - -protoc \ - -I=/proto/include \ - --grpc-gateway_out ${GOPATH}/src \ - --grpc-gateway_opt logtostderr=true \ - --grpc-gateway_opt allow_delete_body=true \ - --openapiv2_out ${OPENAPI_PATH} \ - --openapiv2_opt logtostderr=true \ - --openapiv2_opt allow_delete_body=true \ - --zitadel_out=${GOPATH}/src \ - --validate_out=lang=go:${GOPATH}/src \ - ${PROTO_PATH}/settings/v2alpha/settings_service.proto - -echo "done generating grpc" diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 4cc990b34..e5244cbb1 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -14,6 +14,29 @@ Tracing: Fraction: 1.0 MetricPrefix: zitadel +Telemetry: + # As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints. + # Data is projected by ZITADEL even if Enabled is false. + # This means that switching this to true makes ZITADEL try to send past data. + Enabled: false + # Push telemetry data to all these endpoints at least once using an HTTP POST request. + # If one endpoint returns an unsuccessful response code or times out, + # ZITADEL retries to push the data point to all configured endpoints until it succeeds. + # Configure delivery guarantees and intervals in the section Projections.Customizations.Telemetry + # The endpoints can be reconfigured at runtime. + # Ten redirects are followed. + # If you change this configuration at runtime, remaining data that is not successfully delivered to the old endpoints is sent to the new endpoints. + Endpoints: + - https://httpbin.org/post + # These headers are sent with every request to the configured endpoints. + Headers: + # single-value: "single-value" + # multi-value: + # - "multi-value-1" + # - "multi-value-2" + # The maximum number of data points that are queried before they are sent to the configured endpoints. + Limit: 100 # ZITADEL_TELEMETRY_LIMIT + # Port ZITADEL will listen on Port: 8080 # Port ZITADEL is exposed on, it can differ from port e.g. if you proxy the traffic @@ -169,17 +192,29 @@ Projections: BulkLimit: 2000 # The Notifications projection is used for sending emails and SMS to users Notifications: - # As notification projections don't result in database statements, retries don't have an effect + # As notification projections don't result in database statements, retries don't have any effects MaxFailureCount: 0 # The NotificationsQuotas projection is used for calling quota webhooks NotificationsQuotas: - # Delivery guarantee requirements are probably higher for quota webhooks + # In case of failed deliveries, ZITADEL retries to send the data points to the configured endpoints, but only for active instances. + # An instance is active, as long as there are projected events on the instance, that are not older than the HandleActiveInstances duration. + # Delivery guarantee requirements are higher for quota webhooks # Defaults to 45 days HandleActiveInstances: 1080h - # As quota notification projections don't result in database statements, retries don't have an effect + # As quota notification projections don't result in database statements, retries don't have any effects MaxFailureCount: 0 - # Quota notifications are not so time critical. Setting RequeueEvery every five minutes doesn't annoy the db too much. + # Quota notifications are not so time critical. Setting RequeueEvery every five minutes doesn't annoy the database too much. RequeueEvery: 300s + Telemetry: + # In case of failed deliveries, ZITADEL retries to send the data points to the configured endpoints, but only for active instances. + # An instance is active, as long as there are projected events on the instance, that are not older than the HandleActiveInstances duration. + # Telemetry delivery guarantee requirements are a bit higher than normal data projections, as they are not interactively retryable. + # Defaults to 15 days + HandleActiveInstances: 360h + # As sending telemetry data doesn't result in database statements, retries don't have any effects + MaxFailureCount: 0 + # Telemetry data synchronization is not time critical. Setting RequeueEvery to 55 minutes doesn't annoy the database too much. + RequeueEvery: 3300s Auth: SearchLimit: 1000 @@ -235,6 +270,8 @@ OIDC: Path: /oauth/v2/keys DeviceAuth: Path: /oauth/v2/device_authorization + DefaultLoginURLV2: "/login?authRequest=" + DefaultLogoutURLV2: "/logout?post_logout_redirect=" SAML: ProviderConfig: @@ -320,6 +357,51 @@ SystemDefaults: PasswordSaltCost: 14 MachineKeySize: 2048 ApplicationKeySize: 2048 + PasswordHasher: + # Set hasher configuration for user passwords. + # Passwords previously hashed with a different algorithm + # or cost are automatically re-hashed using this config, + # upon password validation or update. + Hasher: + Algorithm: "bcrypt" + Cost: 14 + + # Other supported Hasher configs: + + # Hasher: + # Algorithm: "argon2i" + # Time: 3 + # Memory: 32768 + # Threads: 4 + + # Hasher: + # Algorithm: "argon2id" + # Time: 1 + # Memory: 65536 + # Threads: 4 + + # Hasher: + # Algorithm: "scrypt" + # Cost: 15 + + # Verifiers enable the possibility of verifying + # passwords that are previously hashed using another + # algorithm then the Hasher. + # This can be used when migrating from one algorithm to another, + # or when importing users with hashed passwords. + # There is no need to enable a Verifier of the same algorithm + # as the Hasher. + # + # The format of the encoded hash strings must comply + # with https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md + # https://passlib.readthedocs.io/en/stable/modular_crypt_format.html + # + # Supported verifiers: (uncomment to enable) + # Verifiers: + # - "argon2" # verifier for both argon2i and argon2id. + # - "bcrypt" + # - "md5" + # - "scrypt" Multifactors: OTP: # If this is empty, the issuer is the requested domain @@ -1037,6 +1119,10 @@ InternalAuthZ: - "org.create" - "policy.read" - "user.self.delete" + - Role: "ORG_USER_SELF_MANAGER" + Permissions: + - "policy.read" + - "user.self.delete" - Role: "PROJECT_OWNER_GLOBAL" Permissions: - "org.global.read" diff --git a/cmd/ready/config.go b/cmd/ready/config.go new file mode 100644 index 000000000..2b7b56ac0 --- /dev/null +++ b/cmd/ready/config.go @@ -0,0 +1,34 @@ +package ready + +import ( + "time" + + "github.com/mitchellh/mapstructure" + "github.com/spf13/viper" + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/config/hook" +) + +type Config struct { + Log *logging.Config + Port uint16 +} + +func MustNewConfig(v *viper.Viper) *Config { + config := new(Config) + err := v.Unmarshal(config, + viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( + hook.Base64ToBytesHookFunc(), + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToTimeHookFunc(time.RFC3339), + mapstructure.StringToSliceHookFunc(","), + )), + ) + logging.OnError(err).Fatal("unable to read default config") + + err = config.Log.SetLogger() + logging.OnError(err).Fatal("unable to set logger") + + return config +} diff --git a/cmd/ready/ready.go b/cmd/ready/ready.go new file mode 100644 index 000000000..2c0e10d07 --- /dev/null +++ b/cmd/ready/ready.go @@ -0,0 +1,37 @@ +package ready + +import ( + "net" + "net/http" + "os" + "strconv" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/zitadel/logging" +) + +func New() *cobra.Command { + return &cobra.Command{ + Use: "ready", + Short: "Checks if zitadel is ready", + Long: "Checks if zitadel is ready", + Run: func(cmd *cobra.Command, args []string) { + config := MustNewConfig(viper.GetViper()) + if !ready(config) { + os.Exit(1) + } + }, + } +} + +func ready(config *Config) bool { + res, err := http.Get("http://" + net.JoinHostPort("localhost", strconv.Itoa(int(config.Port))) + "/debug/ready") + if err != nil { + logging.WithError(err).Warn("ready check failed") + return false + } + defer res.Body.Close() + logging.WithFields("status", res.StatusCode).Warn("ready check failed") + return res.StatusCode == 200 +} diff --git a/cmd/setup/03.go b/cmd/setup/03.go index ca1e0e21c..867e9d498 100644 --- a/cmd/setup/03.go +++ b/cmd/setup/03.go @@ -88,6 +88,9 @@ func (mig *FirstInstance) Execute(ctx context.Context) error { nil, nil, nil, + 0, + 0, + 0, ) if err != nil { return err diff --git a/cmd/setup/config_change.go b/cmd/setup/config_change.go index 14a6849ce..28d66394c 100644 --- a/cmd/setup/config_change.go +++ b/cmd/setup/config_change.go @@ -17,6 +17,7 @@ type externalConfigChange struct { currentExternalDomain string currentExternalSecure bool currentExternalPort uint16 + defaults systemdefaults.SystemDefaults } func (mig *externalConfigChange) SetLastExecution(lastRun map[string]interface{}) { @@ -35,7 +36,7 @@ func (mig *externalConfigChange) Check() bool { func (mig *externalConfigChange) Execute(ctx context.Context) error { cmd, err := command.StartCommands( mig.es, - systemdefaults.SystemDefaults{}, + mig.defaults, nil, nil, nil, @@ -53,6 +54,9 @@ func (mig *externalConfigChange) Execute(ctx context.Context) error { nil, nil, nil, + 0, + 0, + 0, ) if err != nil { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 76f9637a2..25f2f4fa4 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -104,6 +104,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { ExternalDomain: config.ExternalDomain, ExternalPort: config.ExternalPort, ExternalSecure: config.ExternalSecure, + defaults: config.SystemDefaults, }, &projectionTables{ es: eventstoreClient, diff --git a/cmd/start/config.go b/cmd/start/config.go index 3517ef7bb..0739664aa 100644 --- a/cmd/start/config.go +++ b/cmd/start/config.go @@ -1,6 +1,8 @@ package start import ( + "encoding/json" + "reflect" "time" "github.com/mitchellh/mapstructure" @@ -25,6 +27,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/logstore" + "github.com/zitadel/zitadel/internal/notification/handlers" "github.com/zitadel/zitadel/internal/query/projection" static_config "github.com/zitadel/zitadel/internal/static/config" metrics "github.com/zitadel/zitadel/internal/telemetry/metrics/config" @@ -58,13 +61,14 @@ type Config struct { EncryptionKeys *encryptionKeyConfig DefaultInstance command.InstanceSetup AuditLogRetention time.Duration - SystemAPIUsers map[string]*internal_authz.SystemAPIUser + SystemAPIUsers SystemAPIUsers CustomerPortal string Machine *id.Config Actions *actions.Config Eventstore *eventstore.Config LogStore *logstore.Configs Quotas *QuotasConfig + Telemetry *handlers.TelemetryPusherConfig } type QuotasConfig struct { @@ -83,6 +87,7 @@ func MustNewConfig(v *viper.Viper) *Config { mapstructure.StringToSliceHookFunc(","), database.DecodeHook, actions.HTTPConfigDecodeHook, + systemAPIUsersDecodeHook, )), ) logging.OnError(err).Fatal("unable to read config") @@ -114,3 +119,22 @@ type encryptionKeyConfig struct { CSRFCookieKeyID string UserAgentCookieKeyID string } + +type SystemAPIUsers map[string]*internal_authz.SystemAPIUser + +func systemAPIUsersDecodeHook(from, to reflect.Value) (any, error) { + if to.Type() != reflect.TypeOf(SystemAPIUsers{}) { + return from.Interface(), nil + } + + data, ok := from.Interface().(string) + if !ok { + return from.Interface(), nil + } + users := make(SystemAPIUsers) + err := json.Unmarshal([]byte(data), &users) + if err != nil { + return nil, err + } + return users, nil +} diff --git a/cmd/start/start.go b/cmd/start/start.go index e91b628d9..b3d24cd2f 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -13,6 +13,8 @@ import ( "time" clockpkg "github.com/benbjohnson/clock" + "github.com/common-nighthawk/go-figure" + "github.com/fatih/color" "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -22,6 +24,7 @@ import ( "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" + "github.com/zitadel/zitadel/cmd/build" "github.com/zitadel/zitadel/cmd/key" cmd_tls "github.com/zitadel/zitadel/cmd/tls" "github.com/zitadel/zitadel/internal/actions" @@ -32,6 +35,7 @@ import ( "github.com/zitadel/zitadel/internal/api/grpc/admin" "github.com/zitadel/zitadel/internal/api/grpc/auth" "github.com/zitadel/zitadel/internal/api/grpc/management" + oidc_v2 "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2" "github.com/zitadel/zitadel/internal/api/grpc/session/v2" "github.com/zitadel/zitadel/internal/api/grpc/settings/v2" "github.com/zitadel/zitadel/internal/api/grpc/system" @@ -110,6 +114,8 @@ type Server struct { } func startZitadel(config *Config, masterKey string, server chan<- *Server) error { + showBasicInformation(config) + ctx := context.Background() dbClient, err := database.Connect(config.Database, false) @@ -192,6 +198,9 @@ func startZitadel(config *Config, masterKey string, server chan<- *Server) error &http.Client{}, permissionCheck, sessionTokenVerifier, + config.OIDC.DefaultAccessTokenLifetime, + config.OIDC.DefaultRefreshTokenExpiration, + config.OIDC.DefaultRefreshTokenIdleExpiration, ) if err != nil { return fmt.Errorf("cannot start commands: %w", err) @@ -207,14 +216,14 @@ func startZitadel(config *Config, masterKey string, server chan<- *Server) error return err } - usageReporter := logstore.UsageReporterFunc(commands.ReportUsage) + usageReporter := logstore.UsageReporterFunc(commands.ReportQuotaUsage) actionsLogstoreSvc := logstore.New(queries, usageReporter, actionsExecutionDBEmitter, actionsExecutionStdoutEmitter) if actionsLogstoreSvc.Enabled() { logging.Warn("execution logs are currently in beta") } actions.SetLogstoreService(actionsLogstoreSvc) - notification.Start(ctx, config.Projections.Customizations["notifications"], config.Projections.Customizations["notificationsquotas"], config.ExternalPort, config.ExternalSecure, commands, queries, eventstoreClient, assets.AssetAPIFromDomain(config.ExternalSecure, config.ExternalPort), config.SystemDefaults.Notifications.FileSystemPath, keys.User, keys.SMTP, keys.SMS) + notification.Start(ctx, config.Projections.Customizations["notifications"], config.Projections.Customizations["notificationsquotas"], config.Projections.Customizations["telemetry"], *config.Telemetry, config.ExternalDomain, config.ExternalPort, config.ExternalSecure, commands, queries, eventstoreClient, assets.AssetAPIFromDomain(config.ExternalSecure, config.ExternalPort), config.SystemDefaults.Notifications.FileSystemPath, keys.User, keys.SMTP, keys.SMS) router := mux.NewRouter() tlsConfig, err := config.TLS.Config() @@ -344,6 +353,7 @@ func startAPIs( if err := apis.RegisterService(ctx, session.CreateServer(commands, queries, permissionCheck)); err != nil { return err } + if err := apis.RegisterService(ctx, settings.CreateServer(commands, queries, config.ExternalSecure)); err != nil { return err } @@ -397,6 +407,11 @@ func startAPIs( apis.RegisterHandlerOnPrefix(login.HandlerPrefix, l.Handler()) apis.HandleFunc(login.EndpointDeviceAuth, login.RedirectDeviceAuthToPrefix) + // After OIDC provider so that the callback endpoint can be used + if err := apis.RegisterService(ctx, oidc_v2.CreateServer(commands, queries, oidcProvider, config.ExternalSecure)); err != nil { + return err + } + // handle grpc at last to be able to handle the root, because grpc and gateway require a lot of different prefixes apis.RouteGRPC() return nil @@ -444,3 +459,29 @@ func shutdownServer(ctx context.Context, server *http.Server) error { logging.New().Info("server shutdown gracefully") return nil } + +func showBasicInformation(startConfig *Config) { + fmt.Println(color.MagentaString(figure.NewFigure("Zitadel", "", true).String())) + http := "http" + if startConfig.TLS.Enabled || startConfig.ExternalSecure { + http = "https" + } + + consoleURL := fmt.Sprintf("%s://%s:%v/ui/console\n", http, startConfig.ExternalDomain, startConfig.ExternalPort) + healthCheckURL := fmt.Sprintf("%s://%s:%v/debug/healthz\n", http, startConfig.ExternalDomain, startConfig.ExternalPort) + + insecure := !startConfig.TLS.Enabled && !startConfig.ExternalSecure + + fmt.Printf(" ===============================================================\n\n") + fmt.Printf(" Version : %s\n", build.Version()) + fmt.Printf(" TLS enabled : %v\n", startConfig.TLS.Enabled) + fmt.Printf(" External Secure : %v\n", startConfig.ExternalSecure) + fmt.Printf(" Console URL : %s", color.BlueString(consoleURL)) + fmt.Printf(" Health Check URL : %s", color.BlueString(healthCheckURL)) + if insecure { + fmt.Printf("\n %s: you're using plain http without TLS. Be aware this is \n", color.RedString("Warning")) + fmt.Printf(" not a secure setup and should only be used for test systems. \n") + fmt.Printf(" Visit: %s \n", color.CyanString("https://zitadel.com/docs/self-hosting/manage/tls_modes")) + } + fmt.Printf("\n ===============================================================\n\n") +} diff --git a/cmd/zitadel.go b/cmd/zitadel.go index 0c839f267..fdddfed00 100644 --- a/cmd/zitadel.go +++ b/cmd/zitadel.go @@ -15,6 +15,7 @@ import ( "github.com/zitadel/zitadel/cmd/build" "github.com/zitadel/zitadel/cmd/initialise" "github.com/zitadel/zitadel/cmd/key" + "github.com/zitadel/zitadel/cmd/ready" "github.com/zitadel/zitadel/cmd/setup" "github.com/zitadel/zitadel/cmd/start" ) @@ -55,6 +56,7 @@ func New(out io.Writer, in io.Reader, args []string, server chan<- *start.Server start.NewStartFromInit(server), start.NewStartFromSetup(server), key.New(), + ready.New(), ) cmd.InitDefaultVersionFlag() diff --git a/console/angular.json b/console/angular.json index 03ab02ddf..076f905fe 100644 --- a/console/angular.json +++ b/console/angular.json @@ -26,6 +26,9 @@ "assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"], "styles": ["src/styles.scss"], "scripts": ["./node_modules/tinycolor2/dist/tinycolor-min.js"], + "stylePreprocessorOptions": { + "includePaths": ["node_modules"] + }, "allowedCommonJsDependencies": [ "fast-sha256", "buffer", @@ -46,7 +49,8 @@ "inline": false }, "styles": { - "inlineCritical": false + "inlineCritical": false, + "minify": false } }, "budgets": [ diff --git a/console/package-lock.json b/console/package-lock.json index e4f541e63..e69de29bb 100644 --- a/console/package-lock.json +++ b/console/package-lock.json @@ -1,16940 +0,0 @@ -{ - "name": "console", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "console", - "version": "0.0.0", - "dependencies": { - "@angular/animations": "^16.1.2", - "@angular/cdk": "^16.1.2", - "@angular/common": "^16.1.2", - "@angular/compiler": "^16.1.2", - "@angular/core": "^16.1.2", - "@angular/forms": "^16.1.2", - "@angular/material": "^16.1.2", - "@angular/material-moment-adapter": "^16.1.2", - "@angular/platform-browser": "^16.1.2", - "@angular/platform-browser-dynamic": "^16.1.2", - "@angular/router": "^16.1.2", - "@angular/service-worker": "^16.1.2", - "@ctrl/ngx-codemirror": "^6.1.0", - "@grpc/grpc-js": "^1.8.14", - "@ngx-translate/core": "^14.0.0", - "angular-oauth2-oidc": "^15.0.1", - "angularx-qrcode": "^16.0.0", - "buffer": "^6.0.3", - "codemirror": "^5.65.8", - "cors": "^2.8.5", - "file-saver": "^2.0.5", - "flag-icons": "^6.6.6", - "google-proto-files": "^3.0.3", - "google-protobuf": "^3.21.2", - "grpc-web": "^1.4.1", - "i18n-iso-countries": "^7.6.0", - "libphonenumber-js": "^1.10.30", - "material-design-icons-iconfont": "^6.1.1", - "moment": "^2.29.4", - "opentype.js": "^1.3.4", - "ngx-color": "^9.0.0", - "rxjs": "~7.8.0", - "tinycolor2": "^1.6.0", - "tslib": "^2.4.1", - "uuid": "^9.0.0", - "zone.js": "~0.13.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^16.1.1", - "@angular-eslint/builder": "16.0.1", - "@angular-eslint/eslint-plugin": "16.0.1", - "@angular-eslint/eslint-plugin-template": "16.0.1", - "@angular-eslint/schematics": "16.0.1", - "@angular-eslint/template-parser": "16.0.1", - "@angular/cli": "^16.1.1", - "@angular/compiler-cli": "^16.1.2", - "@angular/language-service": "^16.1.2", - "@bufbuild/buf": "^1.18.0-1", - "@types/file-saver": "^2.0.2", - "@types/google-protobuf": "^3.15.3", - "@types/jasmine": "~4.3.3", - "@types/jasminewd2": "~2.0.10", - "@types/jsonwebtoken": "^9.0.1", - "@types/node": "^18.15.11", - "@types/opentype.js": "^1.3.4", - "@types/qrcode": "^1.5.0", - "@types/uuid": "^9.0.1", - "@typescript-eslint/eslint-plugin": "^5.59.11", - "@typescript-eslint/parser": "^5.59.5", - "codelyzer": "^6.0.2", - "eslint": "^8.39.0", - "jasmine-core": "~4.6.0", - "jasmine-spec-reporter": "~7.0.0", - "karma": "^6.4.2", - "karma-chrome-launcher": "^3.2.0", - "karma-coverage-istanbul-reporter": "^3.0.3", - "karma-jasmine": "^5.1.0", - "karma-jasmine-html-reporter": "^2.0.0", - "prettier": "^2.8.7", - "prettier-plugin-organize-imports": "^3.2.2", - "protractor": "~7.0.0", - "typescript": "^4.9.5" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@angular-devkit/architect": { - "version": "0.1601.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.1.tgz", - "integrity": "sha512-LUHaxdAZrvh++7/R+/hzVY5moEVVTjd30b25SNNYcNJsWox1Yh9idu1AvtEuZR/A8Jj+sbHnuw0176GsJ78stg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.1.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/build-angular": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.1.1.tgz", - "integrity": "sha512-k+9hQLGgGWHj7NJ7Fm6nwCDsvseKlipKE6Me9ydliNKclwJ0l+ScpXS/iZA1+Geud7IX3McGWf2QemWj1Nds9g==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1601.1", - "@angular-devkit/build-webpack": "0.1601.1", - "@angular-devkit/core": "16.1.1", - "@babel/core": "7.22.5", - "@babel/generator": "7.22.5", - "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.5", - "@babel/plugin-proposal-async-generator-functions": "7.20.7", - "@babel/plugin-transform-async-to-generator": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.5", - "@babel/preset-env": "7.22.5", - "@babel/runtime": "7.22.5", - "@babel/template": "7.22.5", - "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.1.1", - "@vitejs/plugin-basic-ssl": "1.0.1", - "ansi-colors": "4.1.3", - "autoprefixer": "10.4.14", - "babel-loader": "9.1.2", - "babel-plugin-istanbul": "6.1.1", - "browserslist": "^4.21.5", - "cacache": "17.1.3", - "chokidar": "3.5.3", - "copy-webpack-plugin": "11.0.0", - "critters": "0.0.19", - "css-loader": "6.8.1", - "esbuild-wasm": "0.17.19", - "fast-glob": "3.2.12", - "https-proxy-agent": "5.0.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.2.0", - "karma-source-map-support": "1.4.0", - "less": "4.1.3", - "less-loader": "11.1.0", - "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.1", - "magic-string": "0.30.0", - "mini-css-extract-plugin": "2.7.6", - "mrmime": "1.0.1", - "open": "8.4.2", - "ora": "5.4.1", - "parse5-html-rewriting-stream": "7.0.0", - "picomatch": "2.3.1", - "piscina": "3.2.0", - "postcss": "8.4.24", - "postcss-loader": "7.3.2", - "resolve-url-loader": "5.0.0", - "rxjs": "7.8.1", - "sass": "1.63.2", - "sass-loader": "13.3.1", - "semver": "7.5.1", - "source-map-loader": "4.0.1", - "source-map-support": "0.5.21", - "terser": "5.17.7", - "text-table": "0.2.0", - "tree-kill": "1.2.2", - "tslib": "2.5.3", - "vite": "4.3.9", - "webpack": "5.86.0", - "webpack-dev-middleware": "6.1.1", - "webpack-dev-server": "4.15.0", - "webpack-merge": "5.9.0", - "webpack-subresource-integrity": "5.1.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "optionalDependencies": { - "esbuild": "0.17.19" - }, - "peerDependencies": { - "@angular/compiler-cli": "^16.1.0", - "@angular/localize": "^16.1.0", - "@angular/platform-server": "^16.1.0", - "@angular/service-worker": "^16.1.0", - "jest": "^29.5.0", - "jest-environment-jsdom": "^29.5.0", - "karma": "^6.3.0", - "ng-packagr": "^16.1.0", - "protractor": "^7.0.0", - "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.9.3 <5.2" - }, - "peerDependenciesMeta": { - "@angular/localize": { - "optional": true - }, - "@angular/platform-server": { - "optional": true - }, - "@angular/service-worker": { - "optional": true - }, - "jest": { - "optional": true - }, - "jest-environment-jsdom": { - "optional": true - }, - "karma": { - "optional": true - }, - "ng-packagr": { - "optional": true - }, - "protractor": { - "optional": true - }, - "tailwindcss": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", - "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helpers": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1601.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1601.1.tgz", - "integrity": "sha512-J1O+5qiwCYNCFTKtczhWC3wycuks/3GitmbYv3GMSBz2HJU5XSTtGdlkSvkwCocLHa8ggPlnquLsQNjwcd+EQg==", - "dev": true, - "dependencies": { - "@angular-devkit/architect": "0.1601.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^4.0.0" - } - }, - "node_modules/@angular-devkit/core": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.1.tgz", - "integrity": "sha512-rhyY/N4iKbpfKmErmNmAfBLMrc1H8u8NlfcU6lwN6kbBbM8BfvLk9b7g4JXOfiOQfp4BnQ8CFf7xcIUy4++Tog==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/schematics": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.1.1.tgz", - "integrity": "sha512-s8LFr0m4ILEpJuQj78fCWKocnRleA3MWJU1Q5LZloCcUB8fdDvaPNCt5s0VWC2Sp+4OCxJaSN3kjjcFbCYFvTA==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.1.1", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.0", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-eslint/builder": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.0.1.tgz", - "integrity": "sha512-yjFltV+r3YjisVjASMPmWB/ASz39wdh0q5g0l6/4G+8yaxl6hEYs5o0ZOGeGdTFstCql8FGY+QKwKgsq9Ec4QQ==", - "dev": true, - "dependencies": { - "@nx/devkit": "16.0.2", - "nx": "16.0.2" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.0.1.tgz", - "integrity": "sha512-amvTgKHtZoygivW3LAYZ9qjLWsXM7/7eaRvaHdmAEdjyFnYQZ7UbWMPSQNz1mlW/AzTFvk9lGGQORglNOSDnww==", - "dev": true - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.0.1.tgz", - "integrity": "sha512-CM9keS9cH1QAfSVfsvhw/oGCZcP/D8gfekWwVNjN/uEMEAak0czn1KOG7JQkE36NXOGtwCpTspMi1aa9CVKo9g==", - "dev": true, - "dependencies": { - "@angular-eslint/utils": "16.0.1", - "@typescript-eslint/utils": "5.59.2" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.0.1.tgz", - "integrity": "sha512-1hyfs+Iq7K2x3mDDE4985d8vDcMyknbE9HKHKUtRLfLKC9gnV3N5d4+UeySQ7Rrjvgzkc1g9qHADyuhwRWpDSA==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.0.1", - "@angular-eslint/utils": "16.0.1", - "@typescript-eslint/type-utils": "5.59.2", - "@typescript-eslint/utils": "5.59.2", - "aria-query": "5.1.3", - "axobject-query": "3.1.1" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/schematics": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-16.0.1.tgz", - "integrity": "sha512-1oJJEWVbgPkNK1E8rAJfrgxzNWWzJKv3frTHeAm8gvZ7GftYhHjDcrcnxLWrYNxb9+q8Awi0hvGta/4HROmmnA==", - "dev": true, - "dependencies": { - "@angular-eslint/eslint-plugin": "16.0.1", - "@angular-eslint/eslint-plugin-template": "16.0.1", - "@nx/devkit": "16.0.2", - "ignore": "5.2.4", - "nx": "16.0.2", - "strip-json-comments": "3.1.1", - "tmp": "0.2.1" - }, - "peerDependencies": { - "@angular/cli": ">= 16.0.0 < 17.0.0" - } - }, - "node_modules/@angular-eslint/template-parser": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.0.1.tgz", - "integrity": "sha512-x0+SwSeqa3TiVZan6fE5grHsCkjGqU+zAS2DB6wAw5pyvgNAIjrI4cZEQ8pkgHfXe5tuumTKztlkpisah5s/hg==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.0.1", - "eslint-scope": "^7.0.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/utils": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.0.1.tgz", - "integrity": "sha512-2xnJuhIrMZEYK6UyBym6FaFXZgopIIbqfQ4sAtMWY6zYkCEsVUvx5qKIrsnXAwvpDQrv0WiMXteqi/5ICpVMZQ==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.0.1", - "@typescript-eslint/utils": "5.59.2" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.1.2.tgz", - "integrity": "sha512-Q2hdXYKaNGCRQf1G2E1L/P0lw5thAkC0g/L2GdmB+bgyPCTTk1B7WxDN/SVUCfdz1nReZiLepL3Y24RKeQ6Blw==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/core": "16.1.2" - } - }, - "node_modules/@angular/cdk": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.1.2.tgz", - "integrity": "sha512-sUiaY6QgiplSuhzN7Fp5HUW3HPyz3g8ET45W0I2bSiSmSaDEATLWwVXfxSC4/ZL+YdZHoC9LkYKDSktPO2EDaA==", - "dependencies": { - "tslib": "^2.3.0" - }, - "optionalDependencies": { - "parse5": "^7.1.2" - }, - "peerDependencies": { - "@angular/common": "^16.0.0 || ^17.0.0", - "@angular/core": "^16.0.0 || ^17.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/cli": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.1.1.tgz", - "integrity": "sha512-QrTgMqMnamteZu2x3JhLMo6wBjI05zMr9RQfMHWq4UrUpTqBcHAMqJIKSSbvrtuRbolLrQyLorwxzlmEOfEmbQ==", - "dev": true, - "dependencies": { - "@angular-devkit/architect": "0.1601.1", - "@angular-devkit/core": "16.1.1", - "@angular-devkit/schematics": "16.1.1", - "@schematics/angular": "16.1.1", - "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.3", - "ini": "4.1.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.2.0", - "npm-package-arg": "10.1.0", - "npm-pick-manifest": "8.0.1", - "open": "8.4.2", - "ora": "5.4.1", - "pacote": "15.2.0", - "resolve": "1.22.2", - "semver": "7.5.1", - "symbol-observable": "4.0.0", - "yargs": "17.7.2" - }, - "bin": { - "ng": "bin/ng.js" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular/cli/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@angular/common": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.2.tgz", - "integrity": "sha512-MrJ1CUKg4H8fH0Jc771gLceVcawBPjIM6TSLEM7DMeX7SZ6eSU9HAOCTHXBg7Kmb7ZS19G1BQBD/tkjivszk+Q==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/core": "16.1.2", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/compiler": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.1.2.tgz", - "integrity": "sha512-uLUyesolGL8sEb03GfwSFbtTa++XPQyabAUi53Nz5jzRhFzxCa6cO7w4DCxp7yzQM+8jiPKAuw9bQDNv1eYR7A==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/core": "16.1.2" - }, - "peerDependenciesMeta": { - "@angular/core": { - "optional": true - } - } - }, - "node_modules/@angular/compiler-cli": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.1.2.tgz", - "integrity": "sha512-7Z4qPNv6zRTF8U0CEAqJMF2kzyImilOgGwp92PqwhycZIj/MQyN7Txv8uv2rghhCr9jt9bL2vrHPJNGD2UNLxw==", - "dev": true, - "dependencies": { - "@babel/core": "7.21.8", - "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^3.0.0", - "convert-source-map": "^1.5.1", - "reflect-metadata": "^0.1.2", - "semver": "^7.0.0", - "tslib": "^2.3.0", - "yargs": "^17.2.1" - }, - "bin": { - "ng-xi18n": "bundles/src/bin/ng_xi18n.js", - "ngc": "bundles/src/bin/ngc.js", - "ngcc": "bundles/ngcc/index.js" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/compiler": "16.1.2", - "typescript": ">=4.9.3 <5.2" - } - }, - "node_modules/@angular/core": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.1.2.tgz", - "integrity": "sha512-1w8DcSY/ZJT6qBaZWZGNQ50YQ5Cffm7xXSIcjIZeQwQKRAZNlZ1O/pFEer1kvxkAbVsQH3Nf6kB6t8PkNFCWMg==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.13.0" - } - }, - "node_modules/@angular/forms": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.1.2.tgz", - "integrity": "sha512-OyAQRYE6B2NbucoE5KzmxkQqFFlcSnB8/LWS/J9KHGB1QkPdYJCuWSccypeo4YxgVjYCSvHDnO6jBiHDfwDBuQ==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "16.1.2", - "@angular/core": "16.1.2", - "@angular/platform-browser": "16.1.2", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/language-service": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-16.1.2.tgz", - "integrity": "sha512-pCneNUjrr7SYUBeqqznoGA5V+RTRMljrg4WFufth3jtnKRCWE1XR+MYNDGejfOx/mQZNxBsjz4l83FTwiqjsRQ==", - "dev": true, - "engines": { - "node": "^16.14.0 || >=18.10.0" - } - }, - "node_modules/@angular/material": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-16.1.2.tgz", - "integrity": "sha512-lG88yMnlRkPqXxWpT4Uh3YxwQY3xzaV8dP/Rr3Qtlh0yhp2CEWBmC6Cu1VcHpq0G3VLapO61PIzxSj9125CN5Q==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/auto-init": "15.0.0-canary.90291f2e2.0", - "@material/banner": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/button": "15.0.0-canary.90291f2e2.0", - "@material/card": "15.0.0-canary.90291f2e2.0", - "@material/checkbox": "15.0.0-canary.90291f2e2.0", - "@material/chips": "15.0.0-canary.90291f2e2.0", - "@material/circular-progress": "15.0.0-canary.90291f2e2.0", - "@material/data-table": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dialog": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/drawer": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/fab": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/floating-label": "15.0.0-canary.90291f2e2.0", - "@material/form-field": "15.0.0-canary.90291f2e2.0", - "@material/icon-button": "15.0.0-canary.90291f2e2.0", - "@material/image-list": "15.0.0-canary.90291f2e2.0", - "@material/layout-grid": "15.0.0-canary.90291f2e2.0", - "@material/line-ripple": "15.0.0-canary.90291f2e2.0", - "@material/linear-progress": "15.0.0-canary.90291f2e2.0", - "@material/list": "15.0.0-canary.90291f2e2.0", - "@material/menu": "15.0.0-canary.90291f2e2.0", - "@material/menu-surface": "15.0.0-canary.90291f2e2.0", - "@material/notched-outline": "15.0.0-canary.90291f2e2.0", - "@material/radio": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/segmented-button": "15.0.0-canary.90291f2e2.0", - "@material/select": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/slider": "15.0.0-canary.90291f2e2.0", - "@material/snackbar": "15.0.0-canary.90291f2e2.0", - "@material/switch": "15.0.0-canary.90291f2e2.0", - "@material/tab": "15.0.0-canary.90291f2e2.0", - "@material/tab-bar": "15.0.0-canary.90291f2e2.0", - "@material/tab-indicator": "15.0.0-canary.90291f2e2.0", - "@material/tab-scroller": "15.0.0-canary.90291f2e2.0", - "@material/textfield": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tooltip": "15.0.0-canary.90291f2e2.0", - "@material/top-app-bar": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/animations": "^16.0.0 || ^17.0.0", - "@angular/cdk": "16.1.2", - "@angular/common": "^16.0.0 || ^17.0.0", - "@angular/core": "^16.0.0 || ^17.0.0", - "@angular/forms": "^16.0.0 || ^17.0.0", - "@angular/platform-browser": "^16.0.0 || ^17.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/material-moment-adapter": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-16.1.2.tgz", - "integrity": "sha512-6M0Zu1U0InhNpOScDEtI0rm8FK5JojiliTKj73AOy1LWusOeE6fGzE7Y6qHk3tBJWxQH7Z+SRy7c3cqRzlhLqQ==", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": "^16.0.0 || ^17.0.0", - "@angular/material": "16.1.2", - "moment": "^2.18.1" - } - }, - "node_modules/@angular/platform-browser": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.1.2.tgz", - "integrity": "sha512-jFelRYaVaD2F2ph+Z4tsQUxpw1gGiOU0t5i77srrHDtm+KXpERyYbnXQTog+6q+ScNtsB++0JNkiPQV6oOjtIw==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/animations": "16.1.2", - "@angular/common": "16.1.2", - "@angular/core": "16.1.2" - }, - "peerDependenciesMeta": { - "@angular/animations": { - "optional": true - } - } - }, - "node_modules/@angular/platform-browser-dynamic": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.2.tgz", - "integrity": "sha512-gBPvQ2tAGSUK8oCnL15rCzO9/gyzYR8pf6a7kQdDA1Vr3Aj02UCsJOZvedoMxbnGpLtw3JGWMqZ+bvp4/tCw1g==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "16.1.2", - "@angular/compiler": "16.1.2", - "@angular/core": "16.1.2", - "@angular/platform-browser": "16.1.2" - } - }, - "node_modules/@angular/router": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.1.2.tgz", - "integrity": "sha512-0ZiEtJNwYUQewMXxMf2cNHl6N8ZroxC+WS7I6uq3QhPxhbiF0mThRyhRd158rfSVSLEFWKlyZbDQh1ECMSWhDQ==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "16.1.2", - "@angular/core": "16.1.2", - "@angular/platform-browser": "16.1.2", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/service-worker": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-16.1.2.tgz", - "integrity": "sha512-9GsaAu88fYMXS3xre0ZezpjdOPB2nhHaqwvW97xBkXBEeMx1kyxyfN7LjDkVdYIaTRM4HMP92jbSirT6CifAfA==", - "dependencies": { - "tslib": "^2.3.0" - }, - "bin": { - "ngsw-config": "ngsw-config.js" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "16.1.2", - "@angular/core": "16.1.2" - } - }, - "node_modules/@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", - "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", - "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", - "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", - "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz", - "integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.5.tgz", - "integrity": "sha512-1VpEFOIbMRaXyDeUwUfmTIxExLwQ+zkW+Bh5zXpApA3oQedBx9v/updixWxnx/bZpKw7u8VxWjb/qWpIcmPq8A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.0.tgz", - "integrity": "sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "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==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", - "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", - "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz", - "integrity": "sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-wrap-function": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz", - "integrity": "sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", - "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "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==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz", - "integrity": "sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", - "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", - "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", - "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", - "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", - "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", - "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", - "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.5.tgz", - "integrity": "sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", - "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", - "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", - "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", - "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", - "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.5.tgz", - "integrity": "sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", - "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", - "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", - "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", - "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", - "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", - "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", - "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", - "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", - "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", - "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", - "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", - "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", - "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", - "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", - "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", - "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", - "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", - "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", - "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", - "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", - "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", - "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", - "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.5.tgz", - "integrity": "sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", - "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", - "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", - "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", - "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", - "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", - "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", - "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", - "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", - "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", - "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", - "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", - "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", - "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", - "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", - "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", - "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", - "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.22.5", - "@babel/plugin-syntax-import-attributes": "^7.22.5", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.5", - "@babel/plugin-transform-async-to-generator": "^7.22.5", - "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.5", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.5", - "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.5", - "@babel/plugin-transform-dotall-regex": "^7.22.5", - "@babel/plugin-transform-duplicate-keys": "^7.22.5", - "@babel/plugin-transform-dynamic-import": "^7.22.5", - "@babel/plugin-transform-exponentiation-operator": "^7.22.5", - "@babel/plugin-transform-export-namespace-from": "^7.22.5", - "@babel/plugin-transform-for-of": "^7.22.5", - "@babel/plugin-transform-function-name": "^7.22.5", - "@babel/plugin-transform-json-strings": "^7.22.5", - "@babel/plugin-transform-literals": "^7.22.5", - "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", - "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.5", - "@babel/plugin-transform-modules-systemjs": "^7.22.5", - "@babel/plugin-transform-modules-umd": "^7.22.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.22.5", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", - "@babel/plugin-transform-numeric-separator": "^7.22.5", - "@babel/plugin-transform-object-rest-spread": "^7.22.5", - "@babel/plugin-transform-object-super": "^7.22.5", - "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5", - "@babel/plugin-transform-parameters": "^7.22.5", - "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/plugin-transform-private-property-in-object": "^7.22.5", - "@babel/plugin-transform-property-literals": "^7.22.5", - "@babel/plugin-transform-regenerator": "^7.22.5", - "@babel/plugin-transform-reserved-words": "^7.22.5", - "@babel/plugin-transform-shorthand-properties": "^7.22.5", - "@babel/plugin-transform-spread": "^7.22.5", - "@babel/plugin-transform-sticky-regex": "^7.22.5", - "@babel/plugin-transform-template-literals": "^7.22.5", - "@babel/plugin-transform-typeof-symbol": "^7.22.5", - "@babel/plugin-transform-unicode-escapes": "^7.22.5", - "@babel/plugin-transform-unicode-property-regex": "^7.22.5", - "@babel/plugin-transform-unicode-regex": "^7.22.5", - "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.3", - "babel-plugin-polyfill-corejs3": "^0.8.1", - "babel-plugin-polyfill-regenerator": "^0.5.0", - "core-js-compat": "^3.30.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, - "node_modules/@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", - "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bufbuild/buf": { - "version": "1.18.0-1", - "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.18.0-1.tgz", - "integrity": "sha512-Js6BEbjsfM+aFo2bUxfTs0B4htDbjWCKZ8+FHV6YYqiVsin6NGGQsXblJxwt4+16HLfSnrf41RRnwUaBwHqBzQ==", - "dev": true, - "hasInstallScript": true, - "bin": { - "buf": "bin/buf", - "protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking", - "protoc-gen-buf-lint": "bin/protoc-gen-buf-lint" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@bufbuild/buf-darwin-arm64": "1.18.0-1", - "@bufbuild/buf-darwin-x64": "1.18.0-1", - "@bufbuild/buf-linux-aarch64": "1.18.0-1", - "@bufbuild/buf-linux-x64": "1.18.0-1", - "@bufbuild/buf-win32-arm64": "1.18.0-1", - "@bufbuild/buf-win32-x64": "1.18.0-1" - } - }, - "node_modules/@bufbuild/buf-darwin-x64": { - "version": "1.18.0-1", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.18.0-1.tgz", - "integrity": "sha512-tuOnoCqFaUOj9dBuubEve5XGNkjL+zeCW7ETNgmArUlQobEkL2Fza5mi5Fqt90Ommfj1xpc4vaeNz1oSuU3dTw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@ctrl/ngx-codemirror": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@ctrl/ngx-codemirror/-/ngx-codemirror-6.1.0.tgz", - "integrity": "sha512-73QeoNbnluZalWmNw+SOFctsE+oz0+4Bl9KhlJOIfbCPK/U6OIc+vQNr28hMAp15Y/Idde3LntTwLBDFW0bRVA==", - "dependencies": { - "@types/codemirror": "^5.60.5", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": ">=15.0.0-0", - "@angular/forms": ">=15.0.0-0", - "codemirror": "^5.65.9" - } - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz", - "integrity": "sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.8.14", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz", - "integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==", - "dependencies": { - "@grpc/proto-loader": "^0.7.0", - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.7.tgz", - "integrity": "sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==", - "dependencies": { - "@types/long": "^4.0.1", - "lodash.camelcase": "^4.3.0", - "long": "^4.0.0", - "protobufjs": "^7.0.0", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", - "dev": true - }, - "node_modules/@material/animation": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-tr1y4KYZ2Ml9lFU9b91r5jivDCbh0N3Zv6VFe0frphztlZO5Lqx7MCxsliQ7NwQjqpXg3MkD6ZusVNvnMyo+LA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@material/auto-init": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-ZslBlje2LajaL5d7JCxUoWCKOBOsZYT33CamqPoDeY0Cjl77t3O+8B9YPHF8libytI8j9lrrDrTItQr53PHeHw==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/banner": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-mVtGop9rBXRD6UYkMD7y+OJwd3MA73w7BJ/oJIKFij2q2fn/5hZba6vQ6d6YGUGv+iJPP/S/HaiMQuRE5yyoqA==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/button": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/base": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-DNelmohDScmGvWWS/J05dkIJb/dKOVkA6s0URgPrnTFKXNSavPsmwj7hWzYB5kusz3ZrXJBYBJsE6VqkRRXl0w==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@material/button": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-m3YqCh33kcPGYehCKviDy7RxQIEM2m8Exo6AswPPsxd95jSN3rAeF+pXopoXW5QTOqyKHqHymTKTRYYvwvZHYg==", - "dependencies": { - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/card": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-8Z8KQDmEIwt5IK0n+9C9Be9p4mWLKBXILbH+c6XcMCTemmUxH6cTTax1MwuAmqBGuIq3WE3g7qDpdzjFLTC2kw==", - "dependencies": { - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/checkbox": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-hCilHX0vLedMgeRSOskf+JjdfLIUvEg597LEkTJHnTtJkhwypvol8OwP3eqz3TyJ3qGimIi/sFPKdMBn1Uk4AQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/chips": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-TMtlzuadWP/YMRYg8mpqmaD9M9GzRL5ulHHgYO5F4kaZmI3L+3zvaPvUme/x5qwPkIJUO9S21NxxGAsp9X+ZJQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/checkbox": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "safevalues": "^0.3.4", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/circular-progress": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-znCz3cXC8rmC+1k1ZEeZNOhngm7O7kVG2PoANaE79NN9taDtCTyBGGeocJ4Kza3tb01vxJ2/tuQXC39GNFkHFg==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/progress-indicator": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/data-table": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-9YU6KkOeKs2ARPXZdg7Cv6nPwLkEyBIN331ZB92apcbQpTMJMhR3uuW8SSw4p7aXCE6CJjREsCc0KuYAnFSa2A==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/checkbox": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/icon-button": "15.0.0-canary.90291f2e2.0", - "@material/linear-progress": "15.0.0-canary.90291f2e2.0", - "@material/list": "15.0.0-canary.90291f2e2.0", - "@material/menu": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/select": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/density": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-z2L49vc5tbIGe7tUHwbmzoPvOugsTNVP24WWwBwtg9PRuK4Td5HIsMGYqSzSuwFJvDWQK9Ugvl37jGZSv4vxog==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@material/dialog": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-n0o4MELpVqJHbJDPBYeXf3xeL9a8hbzHmfXYLDI1MUhDIr4xgSkckKdCRc2IFda/g7kxjAgcUTga9EFWqns2qA==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/button": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/icon-button": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/dom": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-90JKk/Ncnqn2dKopNxs1uruiiQZzgLTZQF3a8jxa/w3RQd3Ac9ET1KqmaJSfzXaxgebm+1RZfL9lL+ANEfLWwQ==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/drawer": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-7MJbjUxqpQG9J52xWGVKRhSI/0/7Uhf7l2P9VI2WFb5Fz0IeUupXlw2k1Ktb97nxSjMe9OazjtVUgzBNwOad/Q==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/list": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/elevation": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-4eYbCDc6IfgfguNmRc5GT4QMCfOEwj+K3BAraABcbpuCzEQ5nCClsVrPbRLfPnhWbQrFc2/eBglB8wsrNTjVBw==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/fab": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-YJuJRdqe57DnJ4qyc04flknuGeN+7Nc9ciFZE6snPn84wD6J1khscb21yRARbALDki18kbfnJNrNbzHkYaEMZg==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/feature-targeting": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-mjUemPnMLXPooDcPHxxc2uhVUzm7X3NDsE0x0QJnsHDwuejakaRLghVcRDX3x1VmL/p52Eu5HrgW2FryFEiVhQ==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@material/floating-label": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-dYtgNlXkO0H9Vn76oESZZg1KOa2XIOLhVxhV/qPYrhntET534i7TyajmVk54ncuSSoLPZrbrwrhhR2fUJWxZIg==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/focus-ring": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-U7ERDgHi33ZRmqsiO6syFaWsCUGneltX2sYVtLpQnxME7pKFzi22GdUUIslhgHOFjSMBFF9av2Y79VFbyj9BaQ==", - "dependencies": { - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0" - } - }, - "node_modules/@material/form-field": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-KTj+EOobLcPUYy4nR+t0c2Cjvs7jCI4F1w8XuV0bbmSa6Sxh02tMKY2Xa7Lx55A/uUrsUfViMdP60OLzi7HgjQ==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/icon-button": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-bpqiVPkf/LJEP7iIV5VL9Th0chCIQKTeOuw0mK8HmYucuvqq+k76oPsUcE7mvxRvuKyVh6KJ9fTHAkjse0y7cg==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/image-list": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-JobM4lWsf9grgbqrLuUtJ5fr8BkG02r9c2oFMl5++dtjtLdXWnUIWbiofna8CeqDFQCKXsCk4Jw8ydSKZvj/3A==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/layout-grid": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-f5DSHGf1ka6vHu+8VoTvcU9NkR8fdN2wHmPnITZHQXPVvR6SKoyDzdAf2gacmiTYy69ZFmmJeMcdfNnbcPPUJw==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@material/line-ripple": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-cWpS7l/pFg6cUzL7Lx3ywF6RYF6ESYPkiGlDo9kFERv8lVA2/3m4NF4d9b4kC9h9OWx1b1CaUFRFGD07okgI+g==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/linear-progress": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-nK5RYn8NFZi/+fznLYoEdY6tSzXiJqOU0tX5by7hStURhP2g/RM5SQaJwyjEmHdorfCUIStgmKsN4rB5aMnxdw==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/progress-indicator": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/list": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-h2c6G5aPH1bhgl2yBYAW4y86pl+yVl3YdqU0ixemQ5/2uB/t92imUbI+gKH5LzlbuJKenk3rZJ5eaV+t5zTS1A==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/menu": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-yfpBN4Hg59pHMNplh2LIe8t+/qsfyP0iRAtJoCK90SBwX43kv65u22+3vEJmYzm3Ey/m3S3YRFXTFQRQnn9cmA==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/list": "15.0.0-canary.90291f2e2.0", - "@material/menu-surface": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/menu-surface": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-AkRpOjFOJi2ROZPvFo1z8ik61eEyJEew8NuvlzCE4S3BX/RNFrYVh4W5ylo030S01ALCS5zhVOeekxa/4eokZA==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/notched-outline": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-4lpoIoFJ8cb++M1iQpZ+8iypUuTruzyBAkOvoaNjk7EftEV+aS3K6XntGNtlUZoB/fFho3mAUVjT19IHFWD03A==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/floating-label": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/progress-indicator": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-trQLSstZIA0C64adW/HycycD+PtMfg6iZCIVuTNlZr7PR2Yc1EjuGyA7ts+iXBHZ0TxVshRbDYMwcDogP0rc1w==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@material/radio": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-Ypl4BZ9w1NdbiiEUV3Xw2pb97prMPGEE+5Lm719sVsaFmI4yCKgtsWNEbCbKixborh2ZDZWGCzgMyUQHf3a8xA==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/ripple": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-8yCR/V+7SJ9om0cvAOULF/i5+gPQeT+cuPoCZJQRWq9IndfCmQPY3Zmy26reIT/zEyCebAvMG4/WtU4rc+jxyw==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/rtl": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-HkUhD8K03BxWVw21WDViWo01Chi22cZ1rmlsdCtggkxdVjtDhTbYm/3XvRnxt4RVpr6KaYQgRXI/52T5RtBUnw==", - "dependencies": { - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/segmented-button": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-u1DF+jbysX6wCqt7dDnHgEo2XhNrwkqHq6YsMOFVCoo54PHt3gpwhD89DONqQJKspkdvZuxYHzpqRtV0GIzYDQ==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/touch-target": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/select": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-CCaftyi3eIJl2XqBfHbzj8W2jgTMBzSM2+q4WthA+7z0fYQI4JIHQVHO5YKQG5J9MR1VjYQ0Gy0GNotZLAcoOQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/floating-label": "15.0.0-canary.90291f2e2.0", - "@material/line-ripple": "15.0.0-canary.90291f2e2.0", - "@material/list": "15.0.0-canary.90291f2e2.0", - "@material/menu": "15.0.0-canary.90291f2e2.0", - "@material/menu-surface": "15.0.0-canary.90291f2e2.0", - "@material/notched-outline": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/shape": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-UEB168x8ovLvH4eoBtRnoCT9QvnxB/ZMpOKW1+C+xWisis6Wy9AX0wKT5T6wIpffYYCaBJuhI+ExX2134rAxJw==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/slider": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-krbdGHcROlvnZ0X7HT0d+PvJummczeShQeWeV/ZezXnQM7bQoy86qfwtX4ai1dIXYkF9qKTFlta2zZezTJyf5g==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/snackbar": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-f1+HaSaAkALtQqEr6WMUqfwOsJr5nOUjP15GA+sTs9SD7yzwqMeWsVriBdWXVRe0zNgew6sfBM+cLjg2w4VAOQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/button": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/icon-button": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/switch": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-94/+Zp2VjlLVJXY7u8VHPcJMHPRVNAwHydiGrKvnJ+6LfbLxAcILNBP9RVKqqqOWQeDxB4ApUl+0TV2Lj6mOzA==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "safevalues": "^0.3.4", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-zju6UP038Ddi3XAfliYy58A3OvkQ+zSlOdNOd5l82oMArLYEFi3t51QTjKVjV1wokr6ZQ3Chs4kcrgwVTElYtg==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/focus-ring": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/tab-indicator": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab-bar": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-dTC7oGZg6KuDK2OXO7luJWqshtNY2YgImwZbQ9a1vZZrIGMRHdu+ZtP6RVH2srFVlNIWjzcxfLgNrG+U027RdA==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/tab": "15.0.0-canary.90291f2e2.0", - "@material/tab-indicator": "15.0.0-canary.90291f2e2.0", - "@material/tab-scroller": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab-indicator": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-GXdFO6rO1crXcj+todijzZQVACW4EC72XwLAl6z69TKBgZrhwCoZ6RgzX6vIXSs+KoZ0eIyQLr+yQQx1JjDd4w==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tab-scroller": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-R6trOZpkfk54VV0w0NjMMDcZPQgbnARxCoHLrWeSzv5KOMoiDyWji7FFpLc4fynX/F2lNg8xHpEolpugNRW/1g==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/tab": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/textfield": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-ipxPH8DRh9+cn4MOtAYvGsRLP5RJH/gB/BWh/BiJwjI38Djt4FK4LDHbx7fFo/C8hoj7UNs/BWaSLllyxuWKcg==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/density": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/floating-label": "15.0.0-canary.90291f2e2.0", - "@material/line-ripple": "15.0.0-canary.90291f2e2.0", - "@material/notched-outline": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/theme": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-rDSZ0bPoJothI8nRPQWB4Cyu7DTmc8qIuvFm3OOD4uI/2n+yIFqktS6X+6YF82LeKt4uMTZE+Ce/l51bb8UJGA==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/tokens": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-ZTis8UeSRrm/4iQ6BujtcTf1J2bs2H+SAEnugtZSQiX8pyf90gQvylEoTuMPdUs1+YJ273cn04ipHdkq3OHaew==", - "dependencies": { - "@material/elevation": "15.0.0-canary.90291f2e2.0" - } - }, - "node_modules/@material/tooltip": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-H3XsrctgRriNwt++NN+Zy6/JhyRznWo2pXiTFnOlaYwHOiGIFCNZR0A/0vf/3Kpf0GYhTfkJEFJMosUSZidSDg==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/button": "15.0.0-canary.90291f2e2.0", - "@material/dom": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/tokens": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "safevalues": "^0.3.4", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/top-app-bar": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-ZiJjK4WpIsE0MZTWokP9r4C9/oDqzUhKRn3ef2WCeJEIU3Vjg4t0xBTnST2vIrcBGw1s7WP1gfaxb3DSXSxzpw==", - "dependencies": { - "@material/animation": "15.0.0-canary.90291f2e2.0", - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/elevation": "15.0.0-canary.90291f2e2.0", - "@material/ripple": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/shape": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "@material/typography": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/touch-target": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-IpRFf4umZ4ZNxrP+qJkRY9syh7TFZmU4c7EbAlANAJ0/8rlkEo7WJiqa9P1p4nFaT4eMo4n5g+qRI0Dkb9zW5g==", - "dependencies": { - "@material/base": "15.0.0-canary.90291f2e2.0", - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/rtl": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@material/typography": { - "version": "15.0.0-canary.90291f2e2.0", - "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.90291f2e2.0.tgz", - "integrity": "sha512-tv1HWkJYi5T0470k8vbBb+nefdPgsaIO04ocWMf7luvmfE+MZIaR13RxdupLJ4k5otrdydL3/wEaCNhQ+Ipnvw==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.90291f2e2.0", - "@material/theme": "15.0.0-canary.90291f2e2.0", - "tslib": "^2.1.0" - } - }, - "node_modules/@ngtools/webpack": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.1.1.tgz", - "integrity": "sha512-ItW8Hhokk4bQuV8qMpPeNCj0f3LDpddJpd5DwryKb0sSNacGlVff/0nCiKjJFPoCmMSg6ivpkZfqbIyL9RGYXw==", - "dev": true, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "@angular/compiler-cli": "^16.1.0", - "typescript": ">=4.9.3 <5.2", - "webpack": "^5.54.0" - } - }, - "node_modules/@ngx-translate/core": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", - "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": ">=13.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", - "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", - "dev": true, - "dependencies": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", - "dev": true, - "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", - "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", - "dev": true, - "dependencies": { - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", - "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", - "dev": true, - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@nrwl/devkit": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-16.0.2.tgz", - "integrity": "sha512-SAEcImeQHdSTauO05FUn2vVl9/y5Kx1LNCZ4YE+SdY5/QRq18fuo/DCWmjOGG9M8r06vYGsAgMzkiB4soimcyA==", - "dev": true, - "dependencies": { - "@nx/devkit": "16.0.2" - } - }, - "node_modules/@nrwl/tao": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-16.0.2.tgz", - "integrity": "sha512-wimEe4OTpI7/nDK67RnpZpEXCU+fzA0sDgpIhMgbpPd0vPmKgaZv4nbs8zrm0goFlacmmnLaGRhhGYMOxE+1Lg==", - "dev": true, - "dependencies": { - "nx": "16.0.2" - }, - "bin": { - "tao": "index.js" - } - }, - "node_modules/@nx/devkit": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-16.0.2.tgz", - "integrity": "sha512-BY1Bj0BbAl6XJL0O+QGTWPs/3WMJTEQ+Y4Lfoq4dZM7RllE6rAylr54NA2wa4lsgordZhq1+0g5PVhKKvSVRRw==", - "dev": true, - "dependencies": { - "@nrwl/devkit": "16.0.2", - "ejs": "^3.1.7", - "ignore": "^5.0.4", - "semver": "7.3.4", - "tmp": "~0.2.1", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "nx": ">= 15 <= 17" - } - }, - "node_modules/@nx/devkit/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nx/devkit/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nx/devkit/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@nx/nx-darwin-x64": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-16.0.2.tgz", - "integrity": "sha512-r0rfOrZaOyrwFR5a0UT05xkYRumfkP65cRSZM1TjCA027AG9llYtkLT1hlz8uMKt+P12zrWVzXSqGLDi022ZZg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", - "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@schematics/angular": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.1.1.tgz", - "integrity": "sha512-mJo7FxH3dekG7m4hHW5PyWbiCUaU+DSW93j+cikEksda+Qt6NaEX0hM0W3DjH7O+BnEg6dbAEd2GDSN/0XQghw==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.1.1", - "@angular-devkit/schematics": "16.1.1", - "jsonc-parser": "3.2.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", - "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/tuf": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.0.tgz", - "integrity": "sha512-bLzi9GeZgMCvjJeLUIfs8LJYCxrPRA8IXQkzUtaFKKVPTz0mucRyqFcV2U20yg9K+kYAD0YSitzGfRZCFLjdHQ==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.1.0", - "make-fetch-happen": "^11.0.1", - "tuf-js": "^1.1.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "dev": true - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tufjs/canonical-json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", - "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", - "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", - "dev": true, - "dependencies": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/codemirror": { - "version": "5.60.7", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.7.tgz", - "integrity": "sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA==", - "dependencies": { - "@types/tern": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", - "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "node_modules/@types/cors": { - "version": "2.8.13", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", - "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.35", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", - "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/file-saver": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz", - "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==", - "dev": true - }, - "node_modules/@types/google-protobuf": { - "version": "3.15.6", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.6.tgz", - "integrity": "sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw==", - "dev": true - }, - "node_modules/@types/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/jasmine": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.4.tgz", - "integrity": "sha512-DsJbnxCdjmhRP7dXwjD6JcPc+z7V/4mG3VA1cEFec/+R343TaNPnZ9eJzMkjR4T1BYkjkDIUsPDybkDC0qLrvA==", - "dev": true - }, - "node_modules/@types/jasminewd2": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", - "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", - "dev": true, - "dependencies": { - "@types/jasmine": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.16.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.9.tgz", - "integrity": "sha512-IeB32oIV4oGArLrd7znD2rkHQ6EDCM+2Sr76dJnrHwv9OHBTTM6nuDLK9bmikXzPa0ZlWMWtRGo/Uw4mrzQedA==" - }, - "node_modules/@types/opentype.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-1.3.4.tgz", - "integrity": "sha512-6fbXi67I07ugNM+FExwJnfuui2hD7hraD6nqjr3UnqsbBpxSkrtmO6tBubPdNAjqRT9TVkquVkNS9IkgTtq6/w==", - "dev": true - }, - "node_modules/@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true - }, - "node_modules/@types/qrcode": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.0.tgz", - "integrity": "sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.21.tgz", - "integrity": "sha512-DRHyGEr25ra2C4+eU7eiCSto2j9eUa9pR4z5uiLRBXWFlmfMCAeXwecZnAhuB3eOOCA8OkwcNlb6QUkVZFlKTA==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", - "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.0.tgz", - "integrity": "sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.60.0", - "@typescript-eslint/type-utils": "5.60.0", - "@typescript-eslint/utils": "5.60.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.60.0.tgz", - "integrity": "sha512-hakuzcxPwXi2ihf9WQu1BbRj1e/Pd8ZZwVTG9kfbxAMZstKz8/9OoexIwnmLzShtsdap5U/CoQGRCWlSuPbYxQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.60.0", - "@typescript-eslint/visitor-keys": "5.60.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.60.0.tgz", - "integrity": "sha512-X7NsRQddORMYRFH7FWo6sA9Y/zbJ8s1x1RIAtnlj6YprbToTiQnM6vxcMu7iYhdunmoC0rUWlca13D5DVHkK2g==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.60.0", - "@typescript-eslint/utils": "5.60.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.60.0.tgz", - "integrity": "sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.0.tgz", - "integrity": "sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.60.0", - "@typescript-eslint/visitor-keys": "5.60.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.60.0.tgz", - "integrity": "sha512-ba51uMqDtfLQ5+xHtwlO84vkdjrqNzOnqrnwbMHMRY8Tqeme8C2Q8Fc7LajfGR+e3/4LoYiWXUM6BpIIbHJ4hQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.60.0", - "@typescript-eslint/types": "5.60.0", - "@typescript-eslint/typescript-estree": "5.60.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.0.tgz", - "integrity": "sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.60.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz", - "integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/typescript-estree": "5.59.5", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz", - "integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/visitor-keys": "5.59.5" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz", - "integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.2", - "@typescript-eslint/utils": "5.59.2", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz", - "integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz", - "integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/visitor-keys": "5.59.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz", - "integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz", - "integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz", - "integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/visitor-keys": "5.59.5", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz", - "integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.2", - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/typescript-estree": "5.59.2", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz", - "integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/visitor-keys": "5.59.2" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz", - "integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz", - "integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/visitor-keys": "5.59.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz", - "integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz", - "integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.5", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz", - "integrity": "sha512-pcub+YbFtFhaGRTo1832FQHQSHvMrlb43974e2eS8EKleR3p1cDdkJFPci1UhwkEf1J9Bz+wKBSzqpKp7nNj2A==", - "dev": true, - "engines": { - "node": ">=14.6.0" - }, - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.43", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.43.tgz", - "integrity": "sha512-AhFF3mIDfA+jEwQv2WMHmiYhOvmdbh2qhUkDVQfiqzQtUwS4BgoWwom5NpSPg4Ix5vOul+w1690Bt21CkVLpgg==", - "dev": true, - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/adm-zip": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", - "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "depd": "^2.0.0", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/angular-oauth2-oidc": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/angular-oauth2-oidc/-/angular-oauth2-oidc-15.0.1.tgz", - "integrity": "sha512-5gpqO9QL+qFqMItYFHe8F6H5nOIEaowcNUc9iTDs3P1bfVYnoKoVAaijob53PuPTF4YwzdfwKWZi4Mq6P7GENQ==", - "dependencies": { - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/common": ">=14.0.0", - "@angular/core": ">=14.0.0" - } - }, - "node_modules/angularx-qrcode": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/angularx-qrcode/-/angularx-qrcode-16.0.0.tgz", - "integrity": "sha512-j6IndIU3m4zfqSPKraJPFgigdHa+pM3kapRPBnKSwgKNSpljPQu3XNiRUCmQmfGfnh39ShDVca/k091WTjngAA==", - "dependencies": { - "@types/qrcode": "1.5.0", - "qrcode": "1.5.1", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": "^16.0.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/app-root-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", - "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/argparse/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", - "dev": true - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/babel-loader": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", - "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", - "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.2", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.3.tgz", - "integrity": "sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.4.0", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.1.tgz", - "integrity": "sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.0", - "core-js-compat": "^3.30.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.0.tgz", - "integrity": "sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/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", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/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/body-parser/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/bonjour-service": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", - "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", - "dev": true, - "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/browserstack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - } - }, - "node_modules/browserstack/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/browserstack/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/browserstack/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", - "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001487", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001487.tgz", - "integrity": "sha512-83564Z3yWGqXsh2vaH/mhXfEM0wX+NlBCm1jYHOb97TrTWJEmPTccZgeLTPBUUb0PNVo+oomb7wkimZBIERClA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "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/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/codelyzer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz", - "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==", - "dev": true, - "dependencies": { - "@angular/compiler": "9.0.0", - "@angular/core": "9.0.0", - "app-root-path": "^3.0.0", - "aria-query": "^3.0.0", - "axobject-query": "2.0.2", - "css-selector-tokenizer": "^0.7.1", - "cssauron": "^1.4.0", - "damerau-levenshtein": "^1.0.4", - "rxjs": "^6.5.3", - "semver-dsl": "^1.0.1", - "source-map": "^0.5.7", - "sprintf-js": "^1.1.2", - "tslib": "^1.10.0", - "zone.js": "~0.10.3" - }, - "peerDependencies": { - "@angular/compiler": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next", - "@angular/core": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next", - "tslint": "^5.0.0 || ^6.0.0" - } - }, - "node_modules/codelyzer/node_modules/@angular/compiler": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", - "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", - "dev": true, - "peerDependencies": { - "tslib": "^1.10.0" - } - }, - "node_modules/codelyzer/node_modules/@angular/core": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", - "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", - "dev": true, - "peerDependencies": { - "rxjs": "^6.5.3", - "tslib": "^1.10.0", - "zone.js": "~0.10.2" - } - }, - "node_modules/codelyzer/node_modules/aria-query": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==", - "dev": true, - "dependencies": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" - } - }, - "node_modules/codelyzer/node_modules/axobject-query": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", - "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", - "dev": true, - "dependencies": { - "ast-types-flow": "0.0.7" - } - }, - "node_modules/codelyzer/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/codelyzer/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/codelyzer/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/codelyzer/node_modules/zone.js": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", - "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", - "dev": true - }, - "node_modules/codemirror": { - "version": "5.65.13", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.13.tgz", - "integrity": "sha512-SVWEzKXmbHmTQQWaz03Shrh4nybG0wXx2MEu3FO4ezbPW8IbnZEd5iGHGEffSUaitKYa3i+pHpBsSvw8sPHtzg==" - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/compression/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/compression/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/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/connect/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/connect/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/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", - "dev": true, - "dependencies": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/core-js-compat": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.0.tgz", - "integrity": "sha512-hM7YCu1cU6Opx7MXNu0NuumM0ezNeAeRKadixyiQELWY3vT3De9S4J5ZBMraWV2vZnrE1Cirl0GtFtDtMUXzPw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", - "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", - "dev": true, - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - } - }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/critters": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", - "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "css-select": "^5.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.2", - "htmlparser2": "^8.0.2", - "postcss": "^8.4.23", - "pretty-bytes": "^5.3.0" - } - }, - "node_modules/critters/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/critters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/critters/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/critters/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/critters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/critters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.21", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.3", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssauron": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", - "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", - "dev": true, - "dependencies": { - "through": "X.X.X" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", - "dev": true, - "dependencies": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "dev": true, - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/del/node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", - "dev": true, - "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true - }, - "node_modules/diacritics": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", - "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dijkstrajs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", - "dev": true - }, - "node_modules/dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", - "dev": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", - "dev": true, - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", - "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.394", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.394.tgz", - "integrity": "sha512-0IbC2cfr8w5LxTz+nmn2cJTGafsK9iauV2r5A5scfzyovqLrxuLoxOHE5OBobP3oVIggJT+0JfKnw9sm87c8Hw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/engine.io": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", - "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", - "dev": true, - "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.11.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", - "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "dev": true - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "devOptional": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", - "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==", - "dev": true - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dev": true, - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, - "node_modules/esbuild-wasm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.19.tgz", - "integrity": "sha512-X9UQEMJMZXwlGCfqcBmJ1jEa+KrLfd+gCBypO/TSzo5hZvbVwFqpxj1YCuX54ptTF75wxmrgorR4RL40AKtLVg==", - "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/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/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter-asyncresource": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/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/express/node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/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/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-saver": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", - "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/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/finalhandler/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/finalhandler/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flag-icons": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-6.6.6.tgz", - "integrity": "sha512-4lHDKxldnQ7q617pf9Dx9nAetT+9zcMpUexbRrc9kjLw9KJgZ83zA5Dky3Vv7ZDzUjAiZ46x/cy5P0HnEnqA2A==" - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", - "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", - "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", - "dev": true, - "dependencies": { - "minipass": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", - "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.0.tgz", - "integrity": "sha512-AQ1/SB9HH0yCx1jXAT4vmCbTOPe5RQ+kCurjbel5xSCGhebumUv+GJZfa1rEqor3XIViqwSEmlkZCQD43RWrBg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2", - "path-scurry": "^1.7.0" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-proto-files": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/google-proto-files/-/google-proto-files-3.0.3.tgz", - "integrity": "sha512-7JaU/smPA/FpNsCaXyVjitwiQyn5zYC/ETA+xag3ziovBojIWvzevyrbVqhxgnQdgMJ0p1RVSvpzQL6hkg6yGw==", - "dependencies": { - "protobufjs": "^7.0.0", - "walkdir": "^0.4.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/grpc-web": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/grpc-web/-/grpc-web-1.4.2.tgz", - "integrity": "sha512-gUxWq42l5ldaRplcKb4Pw5O4XBONWZgz3vxIIXnfIeJj8Jc3wYiq2O4c9xzx/NGbbPEej4rhI62C9eTENwLGNw==" - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/har-validator/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", - "dev": true, - "dependencies": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" - } - }, - "node_modules/hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true - }, - "node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-entities": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.6.tgz", - "integrity": "sha512-9o0+dcpIw2/HxkNuYKxSJUF/MMRZQECK4GnF+oQOmJ83yCVHTWgCH5aOXxK5bozNRmM8wtgryjHD3uloPBDEGw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/i18n-iso-countries": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.6.0.tgz", - "integrity": "sha512-HPKjOUKS0BkjiY4ayrsuFbu7Ock++pXLs+FAOYl4WfTL5L0ploEH68fiRAP6Zev5g/jvMFt54KcPGJcb942wbg==", - "dependencies": { - "diacritics": "1.3.0" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", - "dev": true, - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, - "node_modules/immutable": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", - "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/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/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true - }, - "node_modules/ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd/node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", - "dev": true, - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/istanbul-lib-source-maps/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/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", - "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jake": { - "version": "10.8.6", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.6.tgz", - "integrity": "sha512-G43Ub9IYEFfu72sua6rzooi8V8Gz2lkfk48rW20vEWCGizeaEPlKB1Kh8JIA84yQbiAEfqlPmSpGgCKKxH3rDA==", - "dev": true, - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jake/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/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", - "dev": true, - "dependencies": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" - }, - "bin": { - "jasmine": "bin/jasmine.js" - } - }, - "node_modules/jasmine-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", - "integrity": "sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ==", - "dev": true - }, - "node_modules/jasmine-spec-reporter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", - "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", - "dev": true, - "dependencies": { - "colors": "1.4.0" - } - }, - "node_modules/jasmine/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jasmine/node_modules/jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true - }, - "node_modules/jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", - "dev": true, - "engines": { - "node": ">= 6.9.x" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", - "dev": true, - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/karma": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", - "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", - "dev": true, - "dependencies": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.4.1", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", - "dev": true, - "dependencies": { - "which": "^1.2.1" - } - }, - "node_modules/karma-chrome-launcher/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/karma-coverage-istanbul-reporter": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/mattlewis92" - } - }, - "node_modules/karma-jasmine": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", - "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", - "dev": true, - "dependencies": { - "jasmine-core": "^4.1.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "karma": "^6.0.0" - } - }, - "node_modules/karma-jasmine-html-reporter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", - "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", - "dev": true, - "peerDependencies": { - "jasmine-core": "^4.0.0", - "karma": "^6.0.0", - "karma-jasmine": "^5.0.0" - } - }, - "node_modules/karma-source-map-support": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", - "dev": true, - "dependencies": { - "source-map-support": "^0.5.5" - } - }, - "node_modules/karma/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/karma/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/karma/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/karma/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/launch-editor": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", - "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", - "dev": true, - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.7.3" - } - }, - "node_modules/less": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", - "dev": true, - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" - } - }, - "node_modules/less-loader": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", - "dev": true, - "dependencies": { - "klona": "^2.0.4" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "less": "^3.5.0 || ^4.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/less/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/less/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "optional": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/less/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/less/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/less/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/libphonenumber-js": { - "version": "1.10.30", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.30.tgz", - "integrity": "sha512-PLGc+xfrQrkya/YK2/5X+bPpxRmyJBHM+xxz9krUdSgk4Vs2ZwxX5/Ow0lv3r9PDlDtNWb4u+it8MY5rZ0IyGw==" - }, - "node_modules/license-webpack-plugin": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", - "dev": true, - "dependencies": { - "webpack-sources": "^3.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-sources": { - "optional": true - } - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lines-and-columns": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", - "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/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/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", - "dev": true, - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/material-colors": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", - "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" - }, - "node_modules/material-design-icons-iconfont": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz", - "integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-collect/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/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-fetch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", - "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", - "dev": true, - "dependencies": { - "minipass": "^5.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/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/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/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/minipass-json-stream/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/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/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/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/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "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/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": 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==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/needle": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", - "dev": true, - "optional": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "optional": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/needle/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/ngx-color": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ngx-color/-/ngx-color-9.0.0.tgz", - "integrity": "sha512-zyAFux+FRI4cACZ7g8DQQsBbNMhqmFkhtUPaxhkiVHhPzWU1iqXP8MqWH6By3guNOCch5oYrYNBWlHToklbdDg==", - "dependencies": { - "@ctrl/tinycolor": "^3.6.0", - "material-colors": "^1.2.6", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": ">=16.0.0-0", - "@angular/core": ">=16.0.0-0" - } - }, - "node_modules/nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], - "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "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==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", - "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^11.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", - "dev": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-package-data": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", - "dev": true, - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-install-checks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", - "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-packlist": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", - "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", - "dev": true, - "dependencies": { - "ignore-walk": "^6.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", - "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", - "dev": true, - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^10.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", - "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", - "dev": true, - "dependencies": { - "make-fetch-happen": "^11.0.0", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^10.0.0", - "proc-log": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nx": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/nx/-/nx-16.0.2.tgz", - "integrity": "sha512-8Z9Bo1D2VbYjyC/F2ONensKjm10snz1UfkzURZiFA+oXikBPldiH1u67TOTpoCYZfyYQg4l6h6EpOaAvHF6Abg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@nrwl/tao": "16.0.2", - "@parcel/watcher": "2.0.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0-rc.18", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.0.0", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^7.0.2", - "dotenv": "~10.0.0", - "enquirer": "~2.3.6", - "fast-glob": "3.2.7", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "3.0.5", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.3.4", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "v8-compile-cache": "2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "16.0.2", - "@nx/nx-darwin-x64": "16.0.2", - "@nx/nx-linux-arm-gnueabihf": "16.0.2", - "@nx/nx-linux-arm64-gnu": "16.0.2", - "@nx/nx-linux-arm64-musl": "16.0.2", - "@nx/nx-linux-x64-gnu": "16.0.2", - "@nx/nx-linux-x64-musl": "16.0.2", - "@nx/nx-win32-arm64-msvc": "16.0.2", - "@nx/nx-win32-x64-msvc": "16.0.2" - }, - "peerDependencies": { - "@swc-node/register": "^1.4.2", - "@swc/core": "^1.2.173" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } - } - }, - "node_modules/nx/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/nx/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/nx/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/nx/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/nx/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/nx/node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nx/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nx/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nx/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/nx/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/nx/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nx/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/nx/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nx/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/opentype.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", - "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", - "dependencies": { - "string.prototype.codepointat": "^0.2.1", - "tiny-inflate": "^1.0.3" - }, - "bin": { - "ot": "bin/ot" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/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/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/pacote": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", - "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", - "dev": true, - "dependencies": { - "@npmcli/git": "^4.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^6.0.1", - "@npmcli/run-script": "^6.0.0", - "cacache": "^17.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^5.0.0", - "npm-package-arg": "^10.0.0", - "npm-packlist": "^7.0.0", - "npm-pick-manifest": "^8.0.0", - "npm-registry-fetch": "^14.0.0", - "proc-log": "^3.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^6.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^1.3.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "lib/bin.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-json/node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "devOptional": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-html-rewriting-stream": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", - "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", - "dev": true, - "dependencies": { - "entities": "^4.3.0", - "parse5": "^7.0.0", - "parse5-sax-parser": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-sax-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", - "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", - "dev": true, - "dependencies": { - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", - "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", - "dev": true, - "dependencies": { - "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", - "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", - "dev": true, - "dependencies": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" - }, - "optionalDependencies": { - "nice-napi": "^1.0.2" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-loader": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.2.tgz", - "integrity": "sha512-c7qDlXErX6n0VT+LUsW+nwefVtTu3ORtVvK8EXuUIDcxo+b/euYqpuHlJAvePb0Af5e8uMjR/13e0lTuYifaig==", - "dev": true, - "dependencies": { - "cosmiconfig": "^8.1.3", - "jiti": "^1.18.2", - "klona": "^2.0.6", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-organize-imports": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.2.tgz", - "integrity": "sha512-e97lE6odGSiHonHJMTYC0q0iLXQyw0u5z/PJpvP/3vRy6/Zi9kLBwFAbEGjDzIowpjQv8b+J04PDamoUSQbzGA==", - "dev": true, - "peerDependencies": { - "@volar/vue-language-plugin-pug": "^1.0.4", - "@volar/vue-typescript": "^1.0.4", - "prettier": ">=2.0", - "typescript": ">=2.9" - }, - "peerDependenciesMeta": { - "@volar/vue-language-plugin-pug": { - "optional": true - }, - "@volar/vue-typescript": { - "optional": true - } - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/protobufjs": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", - "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/protobufjs/node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/protractor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", - "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", - "dev": true, - "dependencies": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=10.13.x" - } - }, - "node_modules/protractor/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/protractor/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/protractor/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/protractor/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "dependencies": { - "source-map": "^0.5.6" - } - }, - "node_modules/protractor/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/protractor/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/protractor/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true, - "engines": { - "node": ">=0.9" - } - }, - "node_modules/qrcode": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz", - "integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==", - "dependencies": { - "dijkstrajs": "^1.0.1", - "encode-utf8": "^1.0.3", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/qrcode/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==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/qrcode/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/qrcode/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/qrcode/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==" - }, - "node_modules/qrcode/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "node_modules/qrcode/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/read-package-json": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", - "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", - "dev": true, - "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^5.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/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.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-url-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", - "dev": true, - "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "3.21.7", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.7.tgz", - "integrity": "sha512-KXPaEuR8FfUoK2uHwNjxTmJ18ApyvD6zJpYv9FOJSqLStmt6xOY84l1IjK2dSolQmoXknrhEFRaPRgOPdqCT5w==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/safevalues": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/safevalues/-/safevalues-0.3.4.tgz", - "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" - }, - "node_modules/sass": { - "version": "1.63.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.2.tgz", - "integrity": "sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww==", - "dev": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-loader": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz", - "integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==", - "dev": true, - "dependencies": { - "klona": "^2.0.6", - "neo-async": "^2.6.2" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } - } - }, - "node_modules/saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/saucelabs/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/saucelabs/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/saucelabs/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true - }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", - "dev": true, - "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "engines": { - "node": ">= 6.9.0" - } - }, - "node_modules/selenium-webdriver/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", - "dev": true, - "dependencies": { - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", - "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-dsl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", - "integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==", - "dev": true, - "dependencies": { - "semver": "^5.3.0" - } - }, - "node_modules/semver-dsl/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/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/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/send/node_modules/debug/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/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/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/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/serve-index/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/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sigstore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.6.0.tgz", - "integrity": "sha512-QODKff/qW/TXOZI6V/Clqu74xnInAS6it05mufj4/fSewexLtfEntgLZZcBtUK44CDQyUE5TUXYy1ARYzlfG9g==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.1.0", - "@sigstore/tuf": "^1.0.0", - "make-fetch-happen": "^11.0.1", - "tuf-js": "^1.1.3" - }, - "bin": { - "sigstore": "bin/sigstore.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socket.io": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz", - "integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "debug": "~4.3.2", - "engine.io": "~6.4.1", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", - "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", - "dev": true, - "dependencies": { - "ws": "~8.11.0" - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dev": true, - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/sockjs/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dev": true, - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-loader": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", - "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.72.1" - } - }, - "node_modules/source-map-loader/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", - "dev": true - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", - "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", - "dev": true, - "dependencies": { - "minipass": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dev": true, - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/streamroller/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/streamroller/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/streamroller/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/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.codepointat": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", - "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "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": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/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/tar/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/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/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/terser": { - "version": "5.17.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.7.tgz", - "integrity": "sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz", - "integrity": "sha512-WiHL3ElchZMsK27P8uIUh4604IgJyAW47LVXGbEoB21DbQcZ+OuMpGjVYnEUaqcWM6dO8uS2qUbA7LSCWqvsbg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" - }, - "node_modules/tinycolor2": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" - }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", - "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "node_modules/tslint/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tslint/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "peer": true - }, - "node_modules/tslint/node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "peer": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tuf-js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", - "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", - "dev": true, - "dependencies": { - "@tufjs/models": "1.0.4", - "debug": "^4.3.4", - "make-fetch-happen": "^11.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ua-parser-js": { - "version": "0.7.35", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", - "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - } - ], - "engines": { - "node": "*" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", - "dev": true, - "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/walkdir": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", - "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webdriver-js-extender": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", - "dev": true, - "dependencies": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", - "dev": true, - "dependencies": { - "adm-zip": "^0.5.2", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/webdriver-manager/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/webdriver-manager/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/webdriver-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/webdriver-manager/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz", - "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.12", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", - "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-server/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==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/webpack-merge": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", - "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-subresource-integrity": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", - "dev": true, - "dependencies": { - "typed-assert": "^1.0.8" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", - "webpack": "^5.12.0" - }, - "peerDependenciesMeta": { - "html-webpack-plugin": { - "optional": true - } - } - }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "node_modules/word-wrap": { - "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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "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==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/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==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/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/wrap-ansi/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==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/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==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "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" - }, - "engines": { - "node": ">=12" - } - }, - "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==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/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==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zone.js": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.13.0.tgz", - "integrity": "sha512-7m3hNNyswsdoDobCkYNAy5WiUulkMd3+fWaGT9ij6iq3Zr/IwJo4RMCYPSDjT+r7tnPErmY9sZpKhWQ8S5k6XQ==", - "dependencies": { - "tslib": "^2.3.0" - } - } - } -} diff --git a/console/src/app/app.module.ts b/console/src/app/app.module.ts index 57138716f..793dfbc22 100644 --- a/console/src/app/app.module.ts +++ b/console/src/app/app.module.ts @@ -1,5 +1,6 @@ import { CommonModule, registerLocaleData } from '@angular/common'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import localePt from '@angular/common/locales/pt'; import localeBg from '@angular/common/locales/bg'; import localeDe from '@angular/common/locales/de'; import localeEn from '@angular/common/locales/en'; @@ -7,6 +8,7 @@ import localeEs from '@angular/common/locales/es'; import localeFr from '@angular/common/locales/fr'; import localeIt from '@angular/common/locales/it'; import localeJa from '@angular/common/locales/ja'; +import localeMk from '@angular/common/locales/mk'; import localePl from '@angular/common/locales/pl'; import localeZh from '@angular/common/locales/zh'; import { APP_INITIALIZER, NgModule } from '@angular/core'; @@ -83,6 +85,10 @@ registerLocaleData(localeZh); i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/zh.json')); registerLocaleData(localeBg); i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/bg.json')); +registerLocaleData(localePt); +i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/pt.json')); +registerLocaleData(localeMk); +i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/mk.json')); export class WebpackTranslateLoader implements TranslateLoader { getTranslation(lang: string): Observable { diff --git a/console/src/app/modules/idp-table/idp-table.component.ts b/console/src/app/modules/idp-table/idp-table.component.ts index 6df954413..0735f0d52 100644 --- a/console/src/app/modules/idp-table/idp-table.component.ts +++ b/console/src/app/modules/idp-table/idp-table.component.ts @@ -1,11 +1,11 @@ import { SelectionModel } from '@angular/cdk/collections'; -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; import { MatLegacyTableDataSource as MatTableDataSource } from '@angular/material/legacy-table'; import { Router, RouterLink } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Duration } from 'google-protobuf/google/protobuf/duration_pb'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { ListProvidersRequest as AdminListProvidersRequest, ListProvidersResponse as AdminListProvidersResponse, @@ -42,7 +42,7 @@ import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component'; templateUrl: './idp-table.component.html', styleUrls: ['./idp-table.component.scss'], }) -export class IdpTableComponent implements OnInit { +export class IdpTableComponent implements OnInit, OnDestroy { @Input() public serviceType!: PolicyComponentServiceType; @Input() service!: AdminService | ManagementService; @ViewChild(PaginatorComponent) public paginator!: PaginatorComponent; @@ -62,6 +62,8 @@ export class IdpTableComponent implements OnInit { public IDPStylingType: any = IDPStylingType; public loginPolicy!: LoginPolicy.AsObject; + private reloadIDPs$: Subject = new Subject(); + constructor( private workflowService: OverlayWorkflowService, public translate: TranslateService, @@ -72,6 +74,16 @@ export class IdpTableComponent implements OnInit { this.selection.changed.subscribe(() => { this.changedSelection.emit(this.selection.selected); }); + + this.reloadIDPs$.subscribe(() => { + this.getIdps() + .then((resp) => { + this.idps = resp; + }) + .catch((error) => { + this.toast.showError(error); + }); + }); } ngOnInit(): void { @@ -85,6 +97,10 @@ export class IdpTableComponent implements OnInit { } } + ngOnDestroy(): void { + this.reloadIDPs$.complete(); + } + public isAllSelected(): boolean { const numSelected = this.selection.selected.length; const numRows = this.dataSource.data.length; @@ -332,13 +348,7 @@ export class IdpTableComponent implements OnInit { this.toast.showInfo('IDP.TOAST.ADDED', true); setTimeout(() => { - this.getIdps() - .then((resp) => { - this.idps = resp; - }) - .catch((error) => { - this.toast.showError(error); - }); + this.reloadIDPs$.next(); }, 2000); }); }) @@ -351,13 +361,7 @@ export class IdpTableComponent implements OnInit { .then(() => { this.toast.showInfo('IDP.TOAST.ADDED', true); setTimeout(() => { - this.getIdps() - .then((resp) => { - this.idps = resp; - }) - .catch((error) => { - this.toast.showError(error); - }); + this.reloadIDPs$.next(); }, 2000); }) .catch((error) => { @@ -370,13 +374,7 @@ export class IdpTableComponent implements OnInit { .then(() => { this.toast.showInfo('IDP.TOAST.ADDED', true); setTimeout(() => { - this.getIdps() - .then((resp) => { - this.idps = resp; - }) - .catch((error) => { - this.toast.showError(error); - }); + this.reloadIDPs$.next(); }, 2000); }) .catch((error) => { @@ -385,72 +383,71 @@ export class IdpTableComponent implements OnInit { } } - public removeIdp(idp: Provider.AsObject): Promise { - switch (this.serviceType) { - case PolicyComponentServiceType.MGMT: - if (this.isDefault) { - return this.addLoginPolicy() - .then(() => { - this.loginPolicy.isDefault = false; - return (this.service as ManagementService) + public removeIdp(idp: Provider.AsObject): void { + const dialogRef = this.dialog.open(WarnDialogComponent, { + data: { + confirmKey: 'ACTIONS.CONTINUE', + cancelKey: 'ACTIONS.CANCEL', + titleKey: 'IDP.REMOVE_WARN_TITLE', + descriptionKey: 'IDP.REMOVE_WARN_DESCRIPTION', + }, + width: '400px', + }); + + dialogRef.afterClosed().subscribe((resp) => { + if (resp) { + switch (this.serviceType) { + case PolicyComponentServiceType.MGMT: + if (this.isDefault) { + this.addLoginPolicy() + .then(() => { + this.loginPolicy.isDefault = false; + return (this.service as ManagementService) + .removeIDPFromLoginPolicy(idp.id) + .then(() => { + this.toast.showInfo('IDP.TOAST.REMOVED', true); + setTimeout(() => { + this.reloadIDPs$.next(); + }, 2000); + }) + .catch((error) => { + this.toast.showError(error); + }); + }) + .catch((error) => { + this.toast.showError(error); + }); + break; + } else { + (this.service as ManagementService) .removeIDPFromLoginPolicy(idp.id) .then(() => { this.toast.showInfo('IDP.TOAST.REMOVED', true); setTimeout(() => { - this.getIdps() - .then((resp) => { - this.idps = resp; - }) - .catch((error) => { - this.toast.showError(error); - }); + this.reloadIDPs$.next(); }, 2000); }) .catch((error) => { this.toast.showError(error); }); - }) - .catch((error) => { - this.toast.showError(error); - }); - } else { - return (this.service as ManagementService) - .removeIDPFromLoginPolicy(idp.id) - .then(() => { - this.toast.showInfo('IDP.TOAST.REMOVED', true); - setTimeout(() => { - this.getIdps() - .then((resp) => { - this.idps = resp; - }) - .catch((error) => { - this.toast.showError(error); - }); - }, 2000); - }) - .catch((error) => { - this.toast.showError(error); - }); + break; + } + case PolicyComponentServiceType.ADMIN: + (this.service as AdminService) + .removeIDPFromLoginPolicy(idp.id) + .then(() => { + this.toast.showInfo('IDP.TOAST.REMOVED', true); + setTimeout(() => { + this.reloadIDPs$.next(); + }, 2000); + }) + .catch((error) => { + this.toast.showError(error); + }); + break; } - case PolicyComponentServiceType.ADMIN: - return (this.service as AdminService) - .removeIDPFromLoginPolicy(idp.id) - .then(() => { - this.toast.showInfo('IDP.TOAST.REMOVED', true); - setTimeout(() => { - this.getIdps() - .then((resp) => { - this.idps = resp; - }) - .catch((error) => { - this.toast.showError(error); - }); - }, 2000); - }) - .catch((error) => { - this.toast.showError(error); - }); - } + } + }); } public isEnabled(idp: Provider.AsObject): boolean { diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.html b/console/src/app/modules/policies/login-policy/login-policy.component.html index 82a006483..7fd7e2627 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.component.html +++ b/console/src/app/modules/policies/login-policy/login-policy.component.html @@ -99,6 +99,28 @@ {{ 'POLICY.DATA.FORCEMFA' | translate }} + add {{ 'ACTIONS.NEW' | translate }} diff --git a/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.html b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.html new file mode 100644 index 000000000..f53717ade --- /dev/null +++ b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.html @@ -0,0 +1,32 @@ +
+ + {{ 'PROJECT.GRANT.CREATE.SEL_ORG_FORMFIELD' | translate }} + + + + + + + +
+
+ {{ org.name }} + + {{ org.primaryDomain }} +
+
+
+
+ + {{ 'PROJECT.GRANT.CREATE.SEL_ORG_DESC' | translate }} + +
+
diff --git a/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.scss b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.scss new file mode 100644 index 000000000..dbf3f4af1 --- /dev/null +++ b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.scss @@ -0,0 +1,38 @@ +.full-width { + width: 100%; +} + +input { + max-width: 500px; +} + +.org-option { + display: flex; + align-items: center; + + .org-option-column { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + width: 100%; + + span { + line-height: normal; + } + + .fill-space { + flex: 1; + } + + .smaller { + font-size: 13px; + } + } +} + +.org-autocomplete-target-desc { + font-size: 14px; + display: block; + margin-top: 0.5rem; +} diff --git a/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.spec.ts b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.spec.ts new file mode 100644 index 000000000..03a2bda40 --- /dev/null +++ b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { SearchOrgAutocompleteComponent } from './search-org-autocomplete.component'; + +describe('SearchOrgComponent', () => { + let component: SearchOrgAutocompleteComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [SearchOrgAutocompleteComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SearchOrgAutocompleteComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.ts b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.ts new file mode 100644 index 000000000..b640c3038 --- /dev/null +++ b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.component.ts @@ -0,0 +1,83 @@ +import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { UntypedFormControl } from '@angular/forms'; +import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatLegacyAutocomplete as MatAutocomplete } from '@angular/material/legacy-autocomplete'; +import { debounceTime, from, map, Subject, switchMap, takeUntil, tap } from 'rxjs'; +import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb'; +import { Org, OrgNameQuery, OrgQuery, OrgState, OrgStateQuery } from 'src/app/proto/generated/zitadel/org_pb'; +import { AuthenticationService } from 'src/app/services/authentication.service'; +import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; + +@Component({ + selector: 'cnsl-search-org-autocomplete', + templateUrl: './search-org-autocomplete.component.html', + styleUrls: ['./search-org-autocomplete.component.scss'], +}) +export class SearchOrgAutocompleteComponent implements OnInit, OnDestroy { + public selectable: boolean = true; + public myControl: UntypedFormControl = new UntypedFormControl(); + public filteredOrgs: Array = []; + public isLoading: boolean = false; + @ViewChild('auto') public matAutocomplete!: MatAutocomplete; + @Output() public selectionChanged: EventEmitter = new EventEmitter(); + + private unsubscribed$: Subject = new Subject(); + constructor(public authService: AuthenticationService, private auth: GrpcAuthService) { + this.myControl.valueChanges + .pipe( + takeUntil(this.unsubscribed$), + debounceTime(200), + tap(() => (this.isLoading = true)), + switchMap((value) => { + const stateQuery = new OrgQuery(); + const orgStateQuery = new OrgStateQuery(); + orgStateQuery.setState(OrgState.ORG_STATE_ACTIVE); + stateQuery.setStateQuery(orgStateQuery); + + let queries: OrgQuery[] = [stateQuery]; + + if (value) { + const nameQuery = new OrgQuery(); + const orgNameQuery = new OrgNameQuery(); + orgNameQuery.setName(value); + orgNameQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE); + nameQuery.setNameQuery(orgNameQuery); + queries = [stateQuery, nameQuery]; + } + + return from(this.auth.listMyProjectOrgs(undefined, 0, queries)).pipe( + map((resp) => { + return resp.resultList.sort((left, right) => left.name.localeCompare(right.name)); + }), + ); + }), + ) + .subscribe((returnValue) => { + this.isLoading = false; + this.filteredOrgs = returnValue; + }); + } + + public ngOnInit(): void { + const query = new OrgQuery(); + const orgStateQuery = new OrgStateQuery(); + orgStateQuery.setState(OrgState.ORG_STATE_ACTIVE); + query.setStateQuery(orgStateQuery); + + this.auth.listMyProjectOrgs(undefined, 0, [query]).then((orgs) => { + this.filteredOrgs = orgs.resultList; + }); + } + + public ngOnDestroy(): void { + this.unsubscribed$.next(); + } + + public displayFn(org?: Org.AsObject): string { + return org ? `${org.name}` : ''; + } + + public selected(event: MatAutocompleteSelectedEvent): void { + this.selectionChanged.emit(event.option.value); + } +} diff --git a/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.module.ts b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.module.ts new file mode 100644 index 000000000..36c99d27f --- /dev/null +++ b/console/src/app/modules/search-org-autocomplete/search-org-autocomplete.module.ts @@ -0,0 +1,32 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatIconModule } from '@angular/material/icon'; +import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete'; +import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button'; +import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips'; +import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; +import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { InputModule } from 'src/app/modules/input/input.module'; + +import { SearchOrgAutocompleteComponent } from './search-org-autocomplete.component'; + +@NgModule({ + declarations: [SearchOrgAutocompleteComponent], + imports: [ + CommonModule, + MatAutocompleteModule, + MatChipsModule, + MatButtonModule, + InputModule, + MatIconModule, + ReactiveFormsModule, + MatProgressSpinnerModule, + FormsModule, + TranslateModule, + MatSelectModule, + ], + exports: [SearchOrgAutocompleteComponent], +}) +export class SearchOrgAutocompleteModule {} diff --git a/console/src/app/pages/domains/domain-verification/domain-verification.component.html b/console/src/app/pages/domains/domain-verification/domain-verification.component.html index 8790d7201..364bcb659 100644 --- a/console/src/app/pages/domains/domain-verification/domain-verification.component.html +++ b/console/src/app/pages/domains/domain-verification/domain-verification.component.html @@ -44,7 +44,7 @@

HTTP TOKEN

-

{{ http.url }}.txt

+

{{ http.url }}

diff --git a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.html b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.html index 17ab85449..0dd00975d 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.html +++ b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.html @@ -6,20 +6,8 @@ >

{{ 'PROJECT.GRANT.CREATE.SEL_ORG' | translate }}

-

{{ 'PROJECT.GRANT.CREATE.SEL_ORG_DESC' | translate }}

- -
- - {{ 'PROJECT.GRANT.CREATE.SEL_ORG_FORMFIELD' | translate }} - - - - -
- - {{ 'PROJECT.GRANT.CREATE.FOR_ORG' | translate }} {{ org.name }} + + {{ 'PROJECT.GRANT.CREATE.FOR_ORG' | translate }} {{ org.name }} - {{ org.primaryDomain }}
@@ -37,7 +25,15 @@
- @@ -46,7 +42,15 @@ - diff --git a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts index 6cb71c63a..ebcab508c 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts +++ b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts @@ -88,6 +88,10 @@ export class ProjectGrantCreateComponent implements OnInit, OnDestroy { } } + public selectOrg(org: Org.AsObject): void { + this.org = org; + } + public selectRoles(roles: string[]): void { this.rolesKeyList = roles; } diff --git a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.module.ts b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.module.ts index e0fcca057..aa0d65d18 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.module.ts +++ b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.module.ts @@ -15,6 +15,7 @@ import { InputModule } from 'src/app/modules/input/input.module'; import { ProjectRolesTableModule } from 'src/app/modules/project-roles-table/project-roles-table.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; +import { SearchOrgAutocompleteModule } from 'src/app/modules/search-org-autocomplete/search-org-autocomplete.module'; import { ProjectGrantCreateRoutingModule } from './project-grant-create-routing.module'; import { ProjectGrantCreateComponent } from './project-grant-create.component'; @@ -38,6 +39,7 @@ import { ProjectGrantCreateComponent } from './project-grant-create.component'; MatProgressSpinnerModule, FormsModule, TranslateModule, + SearchOrgAutocompleteModule, ], }) export default class ProjectGrantCreateModule {} diff --git a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html index 748b20591..b0a9321a3 100644 --- a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html +++ b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html @@ -17,6 +17,7 @@ class="cnsl-action-button" mat-raised-button [routerLink]="['/projects', projectId, 'projectgrants', 'create']" + data-e2e="create-project-grant-button" > add {{ 'ACTIONS.NEW' | translate }} diff --git a/console/src/app/pages/projects/owned-projects/project-role-create/project-role-create.component.html b/console/src/app/pages/projects/owned-projects/project-role-create/project-role-create.component.html index 8e68738c8..0e4437306 100644 --- a/console/src/app/pages/projects/owned-projects/project-role-create/project-role-create.component.html +++ b/console/src/app/pages/projects/owned-projects/project-role-create/project-role-create.component.html @@ -12,15 +12,15 @@
{{ 'PROJECT.ROLE.KEY' | translate }} - + {{ 'PROJECT.ROLE.DISPLAY_NAME' | translate }} - + {{ 'PROJECT.ROLE.GROUP' | translate }} - +
- diff --git a/console/src/app/utils/language.ts b/console/src/app/utils/language.ts index 209312ede..9bc12ab47 100644 --- a/console/src/app/utils/language.ts +++ b/console/src/app/utils/language.ts @@ -1,3 +1,3 @@ -export const supportedLanguages = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh', 'bg']; -export const supportedLanguagesRegexp: RegExp = /de|en|es|fr|it|ja|pl|zh|bg/; +export const supportedLanguages = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh', 'bg', 'pt', 'mk']; +export const supportedLanguagesRegexp: RegExp = /de|en|es|fr|it|ja|pl|zh|bg|pt|mk/; export const fallbackLanguage: string = 'en'; diff --git a/console/src/assets/i18n/bg.json b/console/src/assets/i18n/bg.json index 48723541a..ddfc38083 100644 --- a/console/src/assets/i18n/bg.json +++ b/console/src/assets/i18n/bg.json @@ -1034,7 +1034,9 @@ "ja": "日本語", "pl": "Полски", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "SMTP настройки", @@ -1234,7 +1236,9 @@ "ja": "日本語", "pl": "Полски", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Проверката на имейл е извършена", @@ -1333,6 +1337,8 @@ "ALLOWREGISTER_DESC": "Ако опцията е избрана, в входа се появява допълнителна стъпка за регистрация на потребител.", "FORCEMFA": "Сила MFA", "FORCEMFA_DESC": "Ако опцията е избрана, потребителите трябва да конфигурират втори фактор за влизане.", + "FORCEMFALOCALONLY": "Принудително MFA за локални потребители", + "FORCEMFALOCALONLY_DESC": "Ако е избрана опцията, локалните удостоверени потребители трябва да конфигурират втори фактор за влизане.", "HIDEPASSWORDRESET": "Скриване на нулиране на парола", "HIDEPASSWORDRESET_DESC": "Ако опцията е избрана, потребителят не може да нулира паролата си в процеса на влизане.", "HIDELOGINNAMESUFFIX": "Скриване на суфикса на името за влизане", @@ -1500,12 +1506,11 @@ "SEL_PROJECT": "Търсене на проект", "SEL_ROLES": "Изберете ролите, които искате да бъдат добавени към субсидията", "SEL_USER": "Изберете потребители", - "SEL_ORG": "Задайте домейна", - "SEL_ORG_DESC": "Въведете пълния домейн, за да посочите организацията, която да предоставите.", - "ORG_TITLE": "Организация", + "SEL_ORG": "Търсете организация", + "SEL_ORG_DESC": "Потърсете организацията за отпускане.", "ORG_DESCRIPTION": "На път сте да предоставите потребител за организацията {{name}}.", "ORG_DESCRIPTION_DESC": "Превключете контекста в заглавката по-горе, за да предоставите потребител за друга организация.", - "SEL_ORG_FORMFIELD": "Пълен домейн", + "SEL_ORG_FORMFIELD": "Организация", "SEL_ORG_BUTTON": "Организация на търсенето", "FOR_ORG": "Безвъзмездната помощ е създадена за:" }, @@ -1777,6 +1782,8 @@ "DELETE": "Изтрий", "DELETE_TITLE": "Изтриване на IDP", "DELETE_DESCRIPTION": "На път сте да изтриете доставчик на самоличност. ", + "REMOVE_WARN_TITLE": "Премахване на IDP", + "REMOVE_WARN_DESCRIPTION": "На път сте да премахнете доставчик на самоличност. Това ще премахне избора на наличен IDP за вашите потребители и вече регистрираните потребители няма да могат да влязат отново. Сигурни ли сте, че ще продължите?", "DELETE_SELECTION_TITLE": "Изтриване на IDP", "DELETE_SELECTION_DESCRIPTION": "На път сте да изтриете доставчик на самоличност. ", "EMPTY": "Няма наличен IDP", @@ -2099,7 +2106,9 @@ "ja": "日本語", "pl": "Полски", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "португалски", + "mk": "Македонски" }, "MEMBER": { "ADD": "Добавяне на мениджър", diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 908c68502..18d83c3a4 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -1040,7 +1040,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "SMTP Einstellungen", @@ -1240,7 +1242,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Email Verification erfolgreich", @@ -1337,8 +1341,10 @@ "ALLOWUSERNAMEPASSWORD_DESC": "Der konventionelle Login mit Benutzername und Passwort wird erlaubt.", "ALLOWEXTERNALIDP_DESC": "Der Login wird für die darunter liegenden Identitätsanbieter erlaubt.", "ALLOWREGISTER_DESC": "Ist die Option gewählt, erscheint im Login ein zusätzlicher Schritt zum Registrieren eines Benutzers.", - "FORCEMFA": "Mfa erzwingen", + "FORCEMFA": "MFA erzwingen", "FORCEMFA_DESC": "Ist die Option gewählt, müssen Benutzer einen zweiten Faktor für den Login verwenden.", + "FORCEMFALOCALONLY": "MFA für lokale Users erzwingen", + "FORCEMFALOCALONLY_DESC": "Ist die Option gewählt, müssen lokal authentifizierte Benutzer einen zweiten Faktor für den Login verwenden.", "HIDEPASSWORDRESET": "Passwort vergessen ausblenden", "HIDEPASSWORDRESET_DESC": "Ist die Option gewählt, ist es nicht möglich im Login das Passwort zurück zusetzen via Passwort vergessen Link.", "HIDELOGINNAMESUFFIX": "Loginname Suffix ausblenden", @@ -1506,13 +1512,11 @@ "SEL_ROLES": "Selektiere die gewünschten Rollen für das Erstellen der Berechtigung.", "SEL_PROJECT": "Suchen nach Projekt", "SEL_USER": "Benutzer auswählen", - "SEL_ORG": "Suchen nach Domain", - "SEL_ORG_DESC": "Gebe die vollständige Domain ein, um Resultate zu erhalten.", - "ORG_TITLE": "Organisation", + "SEL_ORG": "Durchsuchen Sie eine Organisation", + "SEL_ORG_DESC": "Suchen Sie nach der zu gewährenden Organisation.", "ORG_DESCRIPTION": "Du bist im Begriff, einen Benutzer für die Organisation {{name}} zu berechtigen.", "ORG_DESCRIPTION_DESC": "Wechsle den Kontext, um die Organisation zu wechseln.", - "SEL_ORG_FORMFIELD": "Vollständige Domain", - "SEL_ORG_BUTTON": "Suche Organisation", + "SEL_ORG_FORMFIELD": "Organisation", "FOR_ORG": "Die Berechtigung wird erstellt für:" }, "DETAIL": { @@ -1784,6 +1788,8 @@ "DELETE": "Löschen", "DELETE_TITLE": "IDP löschen", "DELETE_DESCRIPTION": "Sie sind im Begriff einen Identitätsanbieter zu löschen. Die dadurch hervorgerufenen Änderungen sind unwiderruflich. Wollen Sie dies wirklich tun?", + "REMOVE_WARN_TITLE": "IDP entfernen?", + "REMOVE_WARN_DESCRIPTION": "Sie sind dabei, einen Identitätsanbieter zu entfernen. Dadurch wird die Auswahl des verfügbaren IDP für Ihre Benutzer entfernt und bereits registrierte Benutzer können sich nicht erneut anmelden. Wollen Sie wirklich fortfahren?", "DELETE_SELECTION_TITLE": "Identitätsanbieter löschen", "DELETE_SELECTION_DESCRIPTION": "Sie sind im Begriff mehrere Identitätsanbieter zu löschen. Die dadurch hervorgerufenen Änderungen sind unwiderruflich. Wollen Sie dies wirklich tun?", "EMPTY": "Kein IDP vorhanden", @@ -2109,7 +2115,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "Manager hinzufügen", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 2800d05c6..8ee10db36 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -486,8 +486,8 @@ "CHANGEUSERNAME": "modify", "CHANGEUSERNAME_TITLE": "Change username", "CHANGEUSERNAME_DESC": "Enter the new name in the field below.", - "FIRSTNAME": "First Name", - "LASTNAME": "Last Name", + "FIRSTNAME": "Given Name", + "LASTNAME": "Family Name", "NICKNAME": "Nickname", "DISPLAYNAME": "Display Name", "PREFERRED_LANGUAGE": "Language", @@ -1041,7 +1041,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "SMTP Settings", @@ -1241,7 +1243,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Email verification done", @@ -1294,8 +1298,8 @@ "PC": "Password Change" }, "CHIPS": { - "firstname": "Firstname", - "lastname": "Lastname", + "firstname": "Given name", + "lastname": "Family name", "code": "Code", "preferredLoginName": "Preferred Login Name", "displayName": "Displayname", @@ -1340,6 +1344,8 @@ "ALLOWREGISTER_DESC": "If the option is selected, an additional step for registering a user appears in the login.", "FORCEMFA": "Force MFA", "FORCEMFA_DESC": "If the option is selected, users have to configure a second factor for login.", + "FORCEMFALOCALONLY": "Force MFA for local authenticated users", + "FORCEMFALOCALONLY_DESC": "If the option is selected, local authenticated users have to configure a second factor for login.", "HIDEPASSWORDRESET": "Hide Password reset", "HIDEPASSWORDRESET_DESC": "If the option is selected, the user can't reset his password in the login process.", "HIDELOGINNAMESUFFIX": "Hide Loginname suffix", @@ -1499,7 +1505,7 @@ "GRANT": { "EMPTY": "No granted organization.", "TITLE": "Project Grants", - "DESCRIPTION": "Allow an other organization to use your project.", + "DESCRIPTION": "Allow another organization to use your project.", "EDITTITLE": "Edit roles", "CREATE": { "TITLE": "Create Organization Grant", @@ -1507,13 +1513,11 @@ "SEL_PROJECT": "Search for a project", "SEL_ROLES": "Select the roles you want to be added to the grant", "SEL_USER": "Select users", - "SEL_ORG": "Set the domain", - "SEL_ORG_DESC": "Enter the complete domain to specify the organization to grant.", - "ORG_TITLE": "Organization", + "SEL_ORG": "Search an organization", + "SEL_ORG_DESC": "Search the organization to grant.", "ORG_DESCRIPTION": "You are about to grant a user for the organization {{name}}.", "ORG_DESCRIPTION_DESC": "Switch the context in the header above to grant a user for another organization.", - "SEL_ORG_FORMFIELD": "Complete Domain", - "SEL_ORG_BUTTON": "Search Organization", + "SEL_ORG_FORMFIELD": "Organization", "FOR_ORG": "The grant is created for:" }, "DETAIL": { @@ -1766,8 +1770,8 @@ "DISPLAYNAMEATTRIBUTE": "Displayname attribute", "EMAILATTRIBUTEATTRIBUTE": "Email attribute", "EMAILVERIFIEDATTRIBUTE": "Email verified attribute", - "FIRSTNAMEATTRIBUTE": "Firstname attribute", - "LASTNAMEATTRIBUTE": "Lastname attribute", + "FIRSTNAMEATTRIBUTE": "Given name attribute", + "LASTNAMEATTRIBUTE": "Family name attribute", "NICKNAMEATTRIBUTE": "Nickname attribute", "PHONEATTRIBUTE": "Phone attribute", "PHONEVERIFIEDATTRIBUTE": "Phone verified attribute", @@ -1784,6 +1788,8 @@ "DELETE": "Delete", "DELETE_TITLE": "Delete IDP", "DELETE_DESCRIPTION": "You are about to delete an identity provider. The resulting changes are irrevocable. Do you really want to do this?", + "REMOVE_WARN_TITLE": "Remove IDP", + "REMOVE_WARN_DESCRIPTION": "You are about to remove an identity provider. This will remove the selection of the available IDP for your users and already registered users won't be able to login again. Are you sure to continue?", "DELETE_SELECTION_TITLE": "Delete IDP", "DELETE_SELECTION_DESCRIPTION": "You are about to delete an identity provider. The resulting changes are irrevocable. Do you really want to do this?", "EMPTY": "No IDP available", @@ -2106,7 +2112,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "Add a Manager", diff --git a/console/src/assets/i18n/es.json b/console/src/assets/i18n/es.json index 8fa4a8d1d..9f4fe349f 100644 --- a/console/src/assets/i18n/es.json +++ b/console/src/assets/i18n/es.json @@ -1041,7 +1041,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "Ajustes SMTP", @@ -1241,7 +1243,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Verificación de email realizada", @@ -1340,6 +1344,8 @@ "ALLOWREGISTER_DESC": "Si esta opción es seleccionada, aparece un paso adicional durante el inicio de sesión para registrar un usuario.", "FORCEMFA": "Forzar MFA", "FORCEMFA_DESC": "Si esta opción es seleccionada, los usuarios tendrán que configurar un doble factor para iniciar sesión.", + "FORCEMFALOCALONLY": "Forzar MFA para usuarios locales", + "FORCEMFALOCALONLY_DESC": "Si esta opción es seleccionada, los usuarios autenticados localmente tendrán que configurar un doble factor para iniciar sesión", "HIDEPASSWORDRESET": "Ocultar restablecer contraseña", "HIDEPASSWORDRESET_DESC": "Si esta opción es seleccionada, el usuario no podrá restablecer su contraseña en el proceso de inicio de sesión.", "HIDELOGINNAMESUFFIX": "Ocultar sufijo del nombre de inicio de sesión", @@ -1507,13 +1513,11 @@ "SEL_PROJECT": "Buscar un proyecto", "SEL_ROLES": "Selecciona los roles que quieres que se añadan a la concesión", "SEL_USER": "Seleccionar usuarios", - "SEL_ORG": "Establecer el dominio", - "SEL_ORG_DESC": "Introduce el dominio completo para especificar la organización concesionaria.", - "ORG_TITLE": "Organización", + "SEL_ORG": "Buscar una organización", + "SEL_ORG_DESC": "Busca la organización concesionaria.", "ORG_DESCRIPTION": "Estás a punto de conceder acceso a un usuario para la organización {{name}}.", "ORG_DESCRIPTION_DESC": "Cambia el contexto en la cabecera superior para conceder acceso a un usuario para otra organización.", - "SEL_ORG_FORMFIELD": "Completar dominio", - "SEL_ORG_BUTTON": "Buscar organización", + "SEL_ORG_FORMFIELD": "Organización", "FOR_ORG": "La concesión se creó para:" }, "DETAIL": { @@ -1784,6 +1788,8 @@ "DELETE": "Borrar", "DELETE_TITLE": "Borrar IDP", "DELETE_DESCRIPTION": "Estás a punto de borrar un proveedor de identidad. Los cambios son irrevocables. ¿Estás seguro de que quieres hacer esto?", + "REMOVE_WARN_TITLE": "Quitar desplazado interno", + "REMOVE_WARN_DESCRIPTION": "Está a punto de eliminar un proveedor de identidad. Esto eliminará la selección del IDP disponible para sus usuarios y los usuarios ya registrados no podrán volver a iniciar sesión. ¿Estás seguro de continuar?", "DELETE_SELECTION_TITLE": "Borrar IDP", "DELETE_SELECTION_DESCRIPTION": "Estás a punto de borrar un proveedor de identidad. Los cambios resultantes son irrevocables. ¿Estás seguro de que quieres hacer esto?", "EMPTY": "No hay IDP disponible", @@ -2106,7 +2112,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "Añadir un Mánager", diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json index b5cea8b8d..8abce8f33 100644 --- a/console/src/assets/i18n/fr.json +++ b/console/src/assets/i18n/fr.json @@ -1040,7 +1040,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "Paramètres SMTP", @@ -1240,7 +1242,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Vérification de l'email effectuée", @@ -1339,6 +1343,8 @@ "ALLOWREGISTER_DESC": "Si l'option est sélectionnée, une étape supplémentaire pour l'enregistrement d'un utilisateur apparaît dans la connexion.", "FORCEMFA": "Forcer MFA", "FORCEMFA_DESC": "Si l'option est sélectionnée, les utilisateurs doivent configurer un deuxième facteur pour la connexion.", + "FORCEMFALOCALONLY": "Forcer MFA pour les utilisateurs locaux", + "FORCEMFALOCALONLY_DESC": "Si l'option est sélectionnée, les utilisateurs locaux authentifiés doivent configurer un deuxième facteur pour la connexion.", "HIDEPASSWORDRESET": "Masquer la réinitialisation du mot de passe", "HIDEPASSWORDRESET_DESC": "Si l'option est sélectionnée, l'utilisateur ne peut pas réinitialiser son mot de passe lors du processus de connexion.", "HIDELOGINNAMESUFFIX": "Masquer le suffixe du nom de connexion", @@ -1506,13 +1512,11 @@ "SEL_PROJECT": "Rechercher un projet", "SEL_ROLES": "Sélectionnez les rôles que vous souhaitez ajouter à l'autorisation.", "SEL_USER": "Sélectionnez les utilisateurs", - "SEL_ORG": "Définir le domaine", - "SEL_ORG_DESC": "Entrez le domaine complet pour spécifier l'organisation à accorder.", - "ORG_TITLE": "Organisation", + "SEL_ORG": "Rechercher une organisation", + "SEL_ORG_DESC": "Rechercher l'organisme à accorder", "ORG_DESCRIPTION": "Vous êtes sur le point d'accorder un utilisateur pour l'organisation{{name}}.", "ORG_DESCRIPTION_DESC": "Changez le contexte dans l'en-tête ci-dessus pour accorder un utilisateur pour une autre organisation.", - "SEL_ORG_FORMFIELD": "Domaine complet", - "SEL_ORG_BUTTON": "Rechercher une organisation", + "SEL_ORG_FORMFIELD": "Organisation", "FOR_ORG": "L'autorisation est créée pour" }, "DETAIL": { @@ -1788,6 +1792,8 @@ "DELETE": "Supprimer", "DELETE_TITLE": "Supprimer Idp", "DELETE_DESCRIPTION": "Vous êtes sur le point de supprimer un fournisseur d'identité. Les changements qui en résultent sont irrévocables. Voulez-vous vraiment le faire ?", + "REMOVE_WARN_TITLE": "Supprimer le fournisseur d'identité", + "REMOVE_WARN_DESCRIPTION": "Vous êtes sur le point de supprimer un fournisseur d'identité. Cela supprimera la sélection de l'IDP disponible pour vos utilisateurs et les utilisateurs déjà enregistrés ne pourront plus se reconnecter. Êtes-vous sûr de continuer ?", "DELETE_SELECTION_TITLE": "Supprimer Idp", "DELETE_SELECTION_DESCRIPTION": "Vous êtes sur le point de supprimer un fournisseur d'identité. Les changements qui en résultent sont irrévocables. Voulez-vous vraiment le faire ?", "EMPTY": "Aucun IDP disponible", @@ -2098,7 +2104,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "Ajouter un manager", diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index 2bbeb1355..22e4df93c 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -1040,7 +1040,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "Impostazioni SMTP", @@ -1240,7 +1242,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Verifica dell'e-mail terminata con successo.", @@ -1339,6 +1343,8 @@ "ALLOWREGISTER_DESC": "Se l'opzione \u00e8 selezionata, nel login apparirà un passo aggiuntivo per la registrazione di un utente.", "FORCEMFA": "Forza MFA", "FORCEMFA_DESC": "Se l'opzione \u00e8 selezionata, gli utenti devono configurare un secondo fattore per il login.", + "FORCEMFALOCALONLY": "Forza MFA per gli utenti locali", + "FORCEMFALOCALONLY_DESC": "Se l'opzione è selezionata, gli utenti locali autenticati devono configurare un secondo fattore per l'accesso.", "HIDEPASSWORDRESET": "Nascondi ripristino della password", "HIDEPASSWORDRESET_DESC": "Se l'opzione \u00e8 selezionata, l'utente non pu\u00f2 resettare la sua password nel interfaccia login.", "HIDELOGINNAMESUFFIX": "Nascondi il suffisso del nome utente", @@ -1506,13 +1512,11 @@ "SEL_PROJECT": "Cerca un progetto", "SEL_ROLES": "Seleziona i ruoli che vuoi aggiungere", "SEL_USER": "Seleziona utenti", - "SEL_ORG": "Impostare il dominio", - "SEL_ORG_DESC": "Inserisci il dominio completo per specificare l'organizzazione da concedere.", - "ORG_TITLE": "Organizzazione", + "SEL_ORG": "Cerca un'organizzazione", + "SEL_ORG_DESC": "Cerca l'organizzazione da concedere.", "ORG_DESCRIPTION": "Stai per concedere un utente per l'organizzazione {{name}}.", "ORG_DESCRIPTION_DESC": "Cambia il contesto nell'intestazione qui sopra per concedere un utente per un'altra organizzazione.", - "SEL_ORG_FORMFIELD": "Dominio completo", - "SEL_ORG_BUTTON": "Ricerca organizzazione", + "SEL_ORG_FORMFIELD": "Organizzazione", "FOR_ORG": "Org grant \u00e8 creato per:" }, "DETAIL": { @@ -1788,6 +1792,8 @@ "DELETE": "Rimuovi IDP", "DELETE_TITLE": "Rimuovi IDP", "DELETE_DESCRIPTION": "Stai per rimuovere un fornitore di identit\u00e0. I cambiamenti risultanti sono irrevocabili. Vuoi davvero farlo?", + "REMOVE_WARN_TITLE": "Rimuovi IDP", + "REMOVE_WARN_DESCRIPTION": "Stai per rimuovere un provider di identità. Questo rimuoverà la selezione dell'IDP disponibile per i tuoi utenti e gli utenti già registrati non potranno accedere nuovamente. Sei sicuro di continuare?", "DELETE_SELECTION_TITLE": "Rimuovere IDP", "DELETE_SELECTION_DESCRIPTION": "Stai per rimuovere un fornitore di identit\u00e0. I cambiamenti risultanti sono irrevocabili. Vuoi davvero farlo?", "EMPTY": "Nessun IDP disponible", @@ -2110,7 +2116,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "Aggiungi un manager", diff --git a/console/src/assets/i18n/ja.json b/console/src/assets/i18n/ja.json index dfae99b4b..498d2b805 100644 --- a/console/src/assets/i18n/ja.json +++ b/console/src/assets/i18n/ja.json @@ -1041,7 +1041,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "SMTP設定", @@ -1236,7 +1238,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "メール認証が完了しました", @@ -1335,6 +1339,8 @@ "ALLOWREGISTER_DESC": "このオプションが選択されている場合、ユーザーを登録するための追加のステップがログインに表示されます。", "FORCEMFA": "MFAを強制する", "FORCEMFA_DESC": "このオプションが選択されている場合、ユーザーはログイン用の二要素認証を構成する必要があります。", + "FORCEMFALOCALONLY": "ローカル ユーザーに MFA を強制する", + "FORCEMFALOCALONLY_DESC": "オプションが選択されている場合、ローカル認証されたユーザーはログインの 2 番目の要素を構成する必要があります。", "HIDEPASSWORDRESET": "パスワードリセットを非表示にする", "HIDEPASSWORDRESET_DESC": "このオプションが選択されている場合、ユーザーはログイン過程ででパスワードをリセットできません。", "HIDELOGINNAMESUFFIX": "ログイン名の接尾辞を非表示にする", @@ -1502,13 +1508,11 @@ "SEL_PROJECT": "プロジェクトを検索する", "SEL_ROLES": "許可するロールを選択する", "SEL_USER": "ユーザーを選択する", - "SEL_ORG": "ドメインを設定する", - "SEL_ORG_DESC": "完全なドメインを入力して、アクセスを許可する組織を指定する。", - "ORG_TITLE": "組織", + "SEL_ORG": "組織を検索する", + "SEL_ORG_DESC": "付与する組織を検索する", "ORG_DESCRIPTION": "組織 {{name}} にユーザーをグラントします。", "ORG_DESCRIPTION_DESC": "上記のヘッダーのコンテキストを切り替えることで、別組織のユーザーにグラントできます。", - "SEL_ORG_FORMFIELD": "完全なドメイン", - "SEL_ORG_BUTTON": "組織を検索する", + "SEL_ORG_FORMFIELD": "組織", "FOR_ORG": "グラントが以下に対して作成されます:" }, "DETAIL": { @@ -1779,6 +1783,8 @@ "DELETE": "削除", "DELETE_TITLE": "IDPの削除", "DELETE_DESCRIPTION": "IDプロバイダーを削除しようとしています。変更は取消できません。本当によろしいですか?", + "REMOVE_WARN_TITLE": "IDPを削除する", + "REMOVE_WARN_DESCRIPTION": "ID プロバイダーを削除しようとしています。これにより、ユーザーが使用できる IDP の選択が削除され、すでに登録されているユーザーは再度ログインできなくなります。続けてもよろしいですか?", "DELETE_SELECTION_TITLE": "IDPの削除", "DELETE_SELECTION_DESCRIPTION": "IDプロバイダーを削除しようとしています。変更は取消できません。本当によろしいですか?", "EMPTY": "IDPは利用できません", @@ -2101,7 +2107,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "マネージャーを追加する", diff --git a/console/src/assets/i18n/mk.json b/console/src/assets/i18n/mk.json new file mode 100644 index 000000000..b511a8ced --- /dev/null +++ b/console/src/assets/i18n/mk.json @@ -0,0 +1,2192 @@ +{ + "APP_NAME": "ZITADEL", + "PAGINATOR": { + "PREVIOUS": "Претходно", + "NEXT": "Следно", + "COUNT": "Вкупнo резултати", + "MORE": "Повеќе" + }, + "FOOTER": { + "LINKS": { + "CONTACT": "Контакт", + "TOS": "Услови за користење", + "PP": "Политика на приватност" + }, + "THEME": { + "DARK": "Темно", + "LIGHT": "Светло" + } + }, + "HOME": { + "WELCOME": "Започнете со ZITADEL", + "DISCLAIMER": "ZITADEL ги третира вашите податоци доверливо и безбедно.", + "DISCLAIMERLINK": "Дополнителни информации", + "DOCUMENTATION": { + "TITLE": "Документација", + "DESCRIPTION": "Започнете брзо со ZITADEL." + }, + "GETSTARTED": { + "TITLE": "Започнете со ZITADEL", + "DESCRIPTION": "Започнете брзо со ZITADEL." + }, + "QUICKSTARTS": { + "LABEL": "Први чекори", + "TITLE": "Брзи чекори", + "DESCRIPTION": "Започнете брзо со ZITADEL." + }, + "SHORTCUTS": { + "SHORTCUTS": "Кратенки", + "SETTINGS": "Достапни кратенки", + "PROJECTS": "Проекти", + "REORDER": "Држете и повчелечете ја ставката за да ја поместите", + "ADD": "Држете и повчелечете ја ставката за да ја додадете" + } + }, + "ONBOARDING": { + "DESCRIPTION": "Вашиот процес на приклучување", + "MOREDESCRIPTION": "повеќе кратенки", + "COMPLETED": "завршено", + "DISMISS": "Не ви благодарам, јас сум професионалец.", + "CARD": { + "TITLE": "Почнете со ZITADEL", + "DESCRIPTION": "Оваа листа со чекори помага при подесувањето на вашата инстанца и ве води низ најважните чекори" + }, + "EVENTS": { + "instance.policy.label.added": { + "title": "Подесете го вашиот бренд", + "description": "Дефинирајте боја и форма за вашиот процез за најава и прикачете ги вашите лого и икони.", + "action": "Подеси го брендот" + }, + "instance.smtp.config.added": { + "title": "Подесете го вашиот SMTP", + "description": "Подесете го вашиот сервер за е-пошта.", + "action": "Подеси SMTP" + }, + "project.added": { + "title": "Креирајте проект", + "description": "Додадете проект и дефинирајте ги неговите улоги и овластувања.", + "action": "Креирај проект" + }, + "project.application.added": { + "title": "Креирајте апликација", + "description": "Креирајте веб, нативна, API или SAML апликација и подесете го вашите автентикациски правила.", + "action": "Креирај апликација" + }, + "user.human.added": { + "title": "Додадете корисници", + "description": "Додадете ги корисниците на вашата апликација", + "action": "Додади корисник" + }, + "user.grant.added": { + "title": "Овластете корисници", + "description": "Дозволете на корисниците да пристапат до вашата апликација и поставете им улога.", + "action": "Овласти корисник" + } + } + }, + "MENU": { + "INSTANCE": "Инстанца", + "DASHBOARD": "Дома", + "PERSONAL_INFO": "Лични информации", + "DOCUMENTATION": "Документација", + "INSTANCEOVERVIEW": "Инстанца", + "ORGS": "Организации", + "VIEWS": "Прегледи", + "EVENTS": "Настани", + "FAILEDEVENTS": "Неуспешни настани", + "ORGANIZATION": "Организација", + "DOMAINS": "Домени", + "PROJECT": "Проекти", + "PROJECTOVERVIEW": "Преглед", + "PROJECTGRANTS": "Овластувања", + "ROLES": "Улоги", + "GRANTEDPROJECT": "Доделени проекти", + "HUMANUSERS": "Корисници", + "MACHINEUSERS": "Сервисни корисници", + "LOGOUT": "Одјави ги сите корисници", + "NEWORG": "Нова организација", + "IAMADMIN": "Вие сте администратор на IAM. Имате проширени овластувања.", + "SHOWORGS": "Прикажи ги сите организации", + "GRANTS": "Овластувања", + "ACTIONS": "Акции", + "PRIVACY": "Приватност", + "TOS": "Услови на користење", + "OPENSHORTCUTSTOOLTIP": "Внесете ? за прикажување на кратенки за тастатура", + "SETTINGS": "Подесувања", + "CUSTOMERPORTAL": "Портал за клиенти" + }, + "ACTIONS": { + "ACTIONS": "Акции", + "FILTER": "Филтер", + "RENAME": "Преименувај", + "SET": "Постави", + "COPY": "Копирај во клипборд", + "COPIED": "Копирано во клипборд.", + "RESET": "Ресетирај", + "RESETDEFAULT": "Ресетирај на стандардно", + "RESETTO": "Ресетирај на: ", + "RESETCURRENT": "Ресетирај на тековно", + "SHOW": "Прикажи", + "HIDE": "Скриј", + "SAVE": "Зачувај", + "SAVENOW": "Зачувај сега", + "NEW": "Нов", + "ADD": "Додади", + "CREATE": "Креирај", + "CONTINUE": "Продолжи", + "BACK": "Назад", + "CLOSE": "Затвори", + "CLEAR": "Исчисти", + "CANCEL": "Откажи", + "INFO": "Инфо", + "OK": "OK", + "SELECT": "Избери", + "VIEW": "Прикажи", + "SELECTIONDELETE": "Избриши избор", + "DELETE": "Избриши", + "REMOVE": "Отстрани", + "VERIFY": "Потврди", + "FINISH": "Заврши", + "FINISHED": "Затвори", + "CHANGE": "Промени", + "REACTIVATE": "Реактивирај", + "ACTIVATE": "Активирај", + "DEACTIVATE": "Деактивирај", + "REFRESH": "Освежи", + "LOGIN": "Најава", + "EDIT": "Уреди", + "PIN": "Закачи / Откачи", + "CONFIGURE": "Конфигурирај", + "SEND": "Испрати", + "NEWVALUE": "Нова вредност", + "RESTORE": "Врати", + "CONTINUEWITHOUTSAVE": "Продолжи без зачувување", + "OF": "од", + "PREVIOUS": "Претходно", + "NEXT": "Следно", + "MORE": "повеќе", + "STEP": "Чекор", + "SETUP": "Подесување", + "UNSAVEDCHANGES": "Незачувани промени", + "UNSAVED": { + "DIALOG": { + "DESCRIPTION": "Дали сте сигурни дека сакате да ја отфрлите оваа нова акција? Вашата акција ќе се изгуби", + "CANCEL": "Откажи", + "DISCARD": "Отфрли" + } + }, + "TABLE": { + "SHOWUSER": "Прикажи корисник {{value}}" + } + }, + "MEMBERROLES": { + "IAM_OWNER": "Има контрола врз целата инстанца, вклучувајќи ги сите организации", + "IAM_OWNER_VIEWER": "Има дозвола за преглед на целата инстанца, вклучувајќи ги сите организации", + "IAM_ORG_MANAGER": "Има дозвола за креирање и менаџирање на организации", + "IAM_USER_MANAGER": "Има дозвола за креирање и менаџирање на корисници", + "ORG_OWNER": "Има дозвола врз целата организација", + "ORG_USER_MANAGER": "Има дозвола за креирање и менаџирање на корисници во организацијата", + "ORG_OWNER_VIEWER": "Има дозвола за преглед на целата организација", + "ORG_USER_PERMISSION_EDITOR": "Има дозвола за менаџирање на овластувања на корисници", + "ORG_PROJECT_PERMISSION_EDITOR": "Има дозвола за менаџирање на овластувања на проекти", + "ORG_PROJECT_CREATOR": "Има дозвола за креирање на сопствени проекти и нивни подесувања", + "PROJECT_OWNER": "Има дозвола врз целиот проект", + "PROJECT_OWNER_VIEWER": "Има дозвола за преглед на целиот проект", + "PROJECT_OWNER_GLOBAL": "Има дозвола врз целиот проект", + "PROJECT_OWNER_VIEWER_GLOBAL": "Има дозвола за преглед на целиот проект", + "PROJECT_GRANT_OWNER": "Има дозвола за менаџирање на овластувања на проектот", + "PROJECT_GRANT_OWNER_VIEWER": "Има дозвола за преглед на овластувањата на проектот" + }, + "OVERLAYS": { + "ORGSWITCHER": { + "TEXT": "Сите подесувања и табели во конзолата за организација се базираат на избраната организација. Кликнете на оваа копче за промена на организација или креирање на нова." + }, + "INSTANCE": { + "TEXT": "Кликнете тука за пристап до подесувањата на инстанцата. Имате пристап до ова копче само доколку имате надградени овластувања." + }, + "PROFILE": { + "TEXT": "Овде можете да се префрлате помеѓу вашите кориснички сметки и да ги менаџирате вашите сесии и профил." + }, + "NAV": { + "TEXT": "Оваа навигација се менува врз основа на избраната организација горе или врз основа на вашата инстанца" + }, + "CONTEXTCHANGED": { + "TEXT": "Контекстот на организацијата е променет." + }, + "SWITCHEDTOINSTANCE": { + "TEXT": "Приказот се смени на инстанца!" + } + }, + "FILTER": { + "TITLE": "Филтер", + "STATE": "Статус", + "DISPLAYNAME": "Име за приказ на корисникот", + "EMAIL": "Е-пошта", + "USERNAME": "Корисничко име", + "ORGNAME": "Име на организацијата", + "PROJECTNAME": "Име на проектот", + "RESOURCEOWNER": "Сопственик на ресурсот", + "METHODS": { + "5": "содржи", + "7": "завршува со", + "1": "е еднакво на" + } + }, + "KEYBOARDSHORTCUTS": { + "TITLE": "Кратенки на тастатура", + "UNDERORGCONTEXT": "Во страници на организацијата", + "SIDEWIDE": "Кратенки кои важат за целиот сајт", + "SHORTCUTS": { + "HOME": "Go to Home", + "INSTANCE": "Go to Iinstance", + "ORG": "Go to Organization", + "ORGSETTINGS": "Go to Organization Settings", + "ORGSWITCHER": "Change Organization", + "ME": "Go To own profile", + "PROJECTS": "Go to Projects", + "USERS": "Go to Users", + "USERGRANTS": "Go to Authorizations", + "ACTIONS": "Go to Actions and Flows", + "DOMAINS": "Go to Domains" + } + }, + "RESOURCEID": "ID на ресурсот", + "NAME": "Име", + "VERSION": "Верзија", + "TABLE": { + "NOROWS": "Нема податоци" + }, + "ERRORS": { + "REQUIRED": "Ве молиме пополнете го ова поле.", + "ATLEASTONE": "Внесете барем една вредност.", + "TOKENINVALID": { + "TITLE": "Вашиот авторизациски токен е истечен.", + "DESCRIPTION": "Кликнете на копчето подолу за повторна најава." + }, + "EXHAUSTED": { + "TITLE": "Вашиот квота за автентицирани барања е надмината.", + "DESCRIPTION": "Отстранете или зголемете ја квотата за оваа ZITADEL инстанца." + }, + "INVALID_FORMAT": "Невалиден формат.", + "NOTANEMAIL": "Внесената вредност не е е-пошта.", + "MINLENGTH": "Мора да биде најмалку {{requiredLength}} карактери долга.", + "UPPERCASEMISSING": "Мора да содржи голема буква.", + "LOWERCASEMISSING": "Мора да содржи мала буква.", + "SYMBOLERROR": "Мора да содржи симбол или знак за интерпункција.", + "NUMBERERROR": "Мора да содржи цифра.", + "PWNOTEQUAL": "Внесените лозинки не се совпаѓаат.", + "PHONE": "Телефонскиот број мора да почне со 00 или +." + }, + "USER": { + "SETTINGS": { + "TITLE": "Подесувања", + "GENERAL": "Општо", + "IDP": "Идентитетски провајдери", + "SECURITY": "Лозинка и Безбедност", + "KEYS": "Клучеви", + "PAT": "Токени за Личен Пристап", + "USERGRANTS": "Овластувања", + "MEMBERSHIPS": "Членства", + "METADATA": "Метаподатоци" + }, + "TITLE": "Лични Информации", + "DESCRIPTION": "Управувајте со вашите информации и подесувања за безбедност.", + "PAGES": { + "LIST": "Корисници", + "TITLE": "Корисник", + "DESCRIPTION": "Креирајте нови корисници во вашата организација и менаџирајте ги постоечките.", + "LISTMACHINE": "Сервисни Корисници", + "DESCRIPTIONMACHINE": "Креирајте и менаџирајте сервисни корисници во вашата организација", + "DETAIL": "Детали", + "CREATE": "Креирај", + "MY": "Мои Информации", + "LOGINNAMES": "Имиња за најавување", + "LOGINMETHODS": "Методи за најавување", + "LOGINNAMESDESC": "Овие се вашите имиња за најавување:", + "NOUSER": "Нема поврзан корисник.", + "REACTIVATE": "Реактивирај", + "DEACTIVATE": "Деактивирај", + "FILTER": "Филтер", + "STATE": "Статус", + "DELETE": "Избриши Корисник", + "UNLOCK": "Отклучи Корисник", + "GENERATESECRET": "Генерирај Клиентска Тајна", + "REMOVESECRET": "Отстрани Клиентска Тајна", + "LOCKEDDESCRIPTION": "Овој корисник е заклучен поради надминатиот максимален број на обиди за најавување и мора да се отклучи за повторна употреба.", + "DELETEACCOUNT": "Избриши Корисничка Сметка", + "DELETEACCOUNT_DESC": "Ако ја извршите оваа акција, ќе бидете одјавени и нема да имате повеќе пристап до вашата корисничка сметка. Оваа акција не може да се поништи, затоа продолжете само ако сте сигурни.", + "DELETEACCOUNT_BTN": "Избриши Корисничка Сметка", + "DELETEACCOUNT_SUCCESS": "Корисничката Сметка е успешно избришана!" + }, + "DETAILS": { + "DATECREATED": "Креирано", + "DATECHANGED": "Променето" + }, + "DIALOG": { + "DELETE_TITLE": "Избриши Корисник", + "DELETE_SELF_TITLE": "Избриши Корисниќка Сметка", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате перманентно да го избришете корисникот?", + "DELETE_SELF_DESCRIPTION": "Дали сте сигурни дека сакате перманентно да ја избришете вашата лична корисничка сметка? Ова ќе ве одјави и ќе го избрише вашето корисничко име. Оваа акција не може да се поништи!", + "DELETE_AUTH_DESCRIPTION": "Дали сте сигурни дека сакате перманентно да ја избришете вашата лична корисничка сметка?", + "TYPEUSERNAME": "Внесете '{{value}}', за да потврдите и да го избришете корисникот.", + "USERNAME": "Корисничко име", + "DELETE_BTN": "Избриши перманентно" + }, + "SENDEMAILDIALOG": { + "TITLE": "Испрати Известување преку Е-пошта", + "DESCRIPTION": "Кликнете на копчето подолу за испраќање на известување до тековната адреса за е-пошта или променете ја адресата за е-пошта во полето.", + "NEWEMAIL": "Нова адреса за е-пошта" + }, + "SECRETDIALOG": { + "CLIENTSECRET": "Клиентска Тајна", + "CLIENTSECRET_DESCRIPTION": "Чувајте ја вашата клиентска тајна на безбедно место бидејќи ќе исчезне откако ќе се затвори дијалогот." + }, + "TABLE": { + "DEACTIVATE": "Деактивирај", + "ACTIVATE": "Активирај", + "CHANGEDATE": "Последна промена", + "CREATIONDATE": "Креирано на", + "TYPES": { + "HUMAN": "Корисници", + "MACHINE": "Сервисни Корисници" + }, + "FILTER": { + "0": "Филтер за Име за Приказ", + "1": "Филтер за Корисничко Име", + "2": "филтер за Име за Приказ", + "3": "филтер за Корисничко Име", + "4": "филтер за Е-пошта", + "5": "филтер за Име за Приказ", + "10": "филтер за име на организација", + "12": "филтер за име на проект" + }, + "EMPTY": "Нема записи" + }, + "PASSWORDLESS": { + "SEND": "Испрати линк за регистрација", + "TABLETYPE": "Тип", + "TABLESTATE": "Статус", + "NAME": "Име", + "EMPTY": "Нема поставен уред", + "TITLE": "Најава без лозинка", + "DESCRIPTION": "Додајте методи за автентикација базирани на WebAuthn за најава на ZITADEL без лозинки.", + "MANAGE_DESCRIPTION": "Управувајте со методите за втор фактор на вашите корисници.", + "U2F": "Додајте метод", + "U2F_DIALOG_TITLE": "Потврдете го автентикаторот", + "U2F_DIALOG_DESCRIPTION": "Внесете име за вашата користена најва без лозинка", + "U2F_SUCCESS": "Најава без лозинка е успешно креирана!", + "U2F_ERROR": "Се појави грешка при подесувањето!", + "U2F_NAME": "Име на автентикатор", + "TYPE": { + "0": "Нема дефиниран MFA", + "1": "Еднократна Лозинка (OTP)", + "2": "Отпечаток на прст, безбедносни клучеви, Face ID и други" + }, + "STATE": { + "0": "Нема Статус", + "1": "Не е Спремно", + "2": "Спремно", + "3": "Избришано" + }, + "DIALOG": { + "DELETE_TITLE": "Отстрани метод за најава без лозинка", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете методот за најава без лозинка? ", + "ADD_TITLE": "Најава без лозинка", + "ADD_DESCRIPTION": "Изберете една од достапните опции за креирање на метод за најава без лозинка.", + "SEND_DESCRIPTION": "Испратете линк за регистрација на вашата е-пошта.", + "SEND": "Испрати линк за регистрација", + "SENT": "Е-поштата беше успешно доставена. Проверете го вашето сандаче за е-пошта за да продолжите со подесувањето.", + "QRCODE_DESCRIPTION": "Генерирајте QR-код за скенирање со друг уред.", + "QRCODE": "Генерирај QR-код", + "QRCODE_SCAN": "Скенирајте го овој QR-код за да продолжите со подесувањето на вашиот уред.", + "NEW_DESCRIPTION": "Користете го овој уред за подесување на најава без лозинка", + "NEW": "Додај ново" + } + }, + "MFA": { + "TABLETYPE": "Тип", + "TABLESTATE": "Статус", + "NAME": "Име", + "EMPTY": "Нема дополнителни фактори", + "TITLE": "Мултифакторска автентикација", + "DESCRIPTION": "Додадете втор фактор за оптимална безбедност на вашиот профил.", + "MANAGE_DESCRIPTION": "Управувајте со методите за втор фактор за вашите корисници.", + "ADD": "Додади фактор", + "OTP": "Апликација за автентикација со OTP (Еднократна Лозинка)", + "OTP_DIALOG_TITLE": "Додади OTP", + "OTP_DIALOG_DESCRIPTION": "Скенирајте го QR-кодот со автентикатор апликација и внесете го кодот подолу за да го верификувате и активирате методот OTP.", + "U2F": "Отпечаток на прст, безбедносни клучеви, Face ID и други", + "U2F_DIALOG_TITLE": "Верифицирај фактор", + "U2F_DIALOG_DESCRIPTION": "Внесете име за вашиот универзален мултифактор.", + "U2F_SUCCESS": "Факторот е успешно додаден!", + "U2F_ERROR": "Се појави грешка при подесувањето!", + "U2F_NAME": "Име на автентикатор", + "TYPE": { + "0": "Нема дефинирана MFA", + "1": "Еднократна лозинка (OTP)", + "2": "Отпечаток на прст, безбедносни клучеви, Face ID и други" + }, + "STATE": { + "0": "Без состојба", + "1": "Не е подготвено", + "2": "Подготвено", + "3": "Избришано" + }, + "DIALOG": { + "MFA_DELETE_TITLE": "Отстрани втор фактор", + "MFA_DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете вториот фактор? ", + "ADD_MFA_TITLE": "Додади втор фактор", + "ADD_MFA_DESCRIPTION": "Изберете една од следниве опции." + } + }, + "EXTERNALIDP": { + "TITLE": "Надворешни IDP", + "DESC": "", + "IDPCONFIGID": "ID на конфигурација на IDP", + "IDPNAME": "Име на IDP", + "USERDISPLAYNAME": "Надворешно име", + "EXTERNALUSERID": "Надоврешен ID на корисник", + "EMPTY": "Не е пронајден надворешен IDP", + "DIALOG": { + "DELETE_TITLE": "Отстрани IDP", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете IDP од корисникот? " + } + }, + "CREATE": { + "TITLE": "Креирај нов корисник", + "DESCRIPTION": "Ве молиме внесете ги потребните информации.", + "NAMEANDEMAILSECTION": "Име и е-пошта", + "GENDERLANGSECTION": "Пол и јазик", + "PHONESECTION": "Телефонски броеви", + "PASSWORDSECTION": "Почетна лозинка", + "ADDRESSANDPHONESECTION": "Телефонски број", + "INITMAILDESCRIPTION": "Ако се изберат двете опции, нема да се испрати е-пошта за иницијализација. Ако се избере само една од опциите, ќе биде испратена е-пошта за обезбедување / верификација на податоците." + }, + "CODEDIALOG": { + "TITLE": "Верификација на телефонски број", + "DESCRIPTION": "Внесете го кодот кој го добивте преку SMS порака за да го верифицирате вашиот телефонски број.", + "CODE": "Код" + }, + "DATA": { + "STATE": "Статус", + "STATE0": "Непознат", + "STATE1": "Активен", + "STATE2": "Неактивен", + "STATE3": "Избришан", + "STATE4": "Заклучен", + "STATE5": "Суспендиран", + "STATE6": "Почетен" + }, + "PROFILE": { + "TITLE": "Профил", + "EMAIL": "Е-пошта", + "PHONE": "Телефонски број", + "PHONE_HINT": "Користете 00 или + и потоа дополнителниот број на земјата, или изберете ја земјата од листата и на крај внесете го телефонскиот број", + "USERNAME": "Корисничко име", + "CHANGEUSERNAME": "промени", + "CHANGEUSERNAME_TITLE": "Промени корисничко име", + "CHANGEUSERNAME_DESC": "Внесете го новото име во полето подолу.", + "FIRSTNAME": "Име", + "LASTNAME": "Презиме", + "NICKNAME": "Прекар", + "DISPLAYNAME": "Име за приказ", + "PREFERRED_LANGUAGE": "Јазик", + "GENDER": "Пол", + "PASSWORD": "Лозинка", + "AVATAR": { + "UPLOADTITLE": "Поставете ја вашата слика за профил", + "UPLOADBTN": "Изберете датотека", + "UPLOAD": "Прикачи", + "CURRENT": "Моментална слика", + "PREVIEW": "Преглед", + "DELETESUCCESS": "Успешно избришано!", + "CROPPERERROR": "Се појави грешка при прикачувањето на вашата датотека. Пробајте со слика од различен формат и големина." + }, + "COUNTRY": "Држава" + }, + "MACHINE": { + "TITLE": "Детали за севисен корисник", + "USERNAME": "Корисничко име", + "NAME": "Име", + "DESCRIPTION": "Опис", + "KEYSTITLE": "Клучеви", + "KEYSDESC": "Дефинирајте ги вашите клучеви и додадете опционален датум на истекување.", + "TOKENSTITLE": "Токени за личен пристап", + "TOKENSDESC": "Токените за личен пристап функционираат како обични OAuth токени за пристап.", + "ID": "ID на клуч", + "TYPE": "Тип", + "EXPIRATIONDATE": "Датум на истекување", + "CHOOSEDATEAFTER": "Внесете валиден датум по", + "CHOOSEEXPIRY": "Изберете датум на истекување", + "CREATIONDATE": "Датум на креирање", + "KEYDETAILS": "Детали за клучот", + "ACCESSTOKENTYPE": "Тип на токен за пристап", + "ACCESSTOKENTYPES": { + "0": "Bearer", + "1": "JWT" + }, + "ADD": { + "TITLE": "Додадете клуч", + "DESCRIPTION": "Изберете го типот на клуч и изберете опционален датум на истекување." + }, + "ADDED": { + "TITLE": "Клучот е креиран", + "DESCRIPTION": "Преземете го клучот бидејќи нема да биде видлив после затворање на овој дијалог!" + }, + "KEYTYPES": { + "1": "JSON" + }, + "DIALOG": { + "DELETE_KEY": { + "TITLE": "Избриши клуч", + "DESCRIPTION": "Дали сакате да го избришете избраниот клуч? Ова не може да се врати." + } + } + }, + "PASSWORD": { + "TITLE": "Лозинка", + "LABEL": "Безбедна лозинка помага за заштита на корисничката сметка", + "DESCRIPTION": "Внесете ја новата лозинка според полисата подолу.", + "OLD": "Моментална лозинка", + "NEW": "Нова лозинка", + "CONFIRM": "Потврди нова лозинка", + "NEWINITIAL": "Лозинка", + "CONFIRMINITIAL": "Потврди лозинка", + "RESET": "Ресетирај моментална лозинка", + "SET": "Постави нова лозинка", + "RESENDNOTIFICATION": "Испрати линк за ресетирање на лозинката", + "REQUIRED": "Некои задолжителни полиња не се пополнети.", + "MINLENGTHERROR": "Мора да биде најмалку {{value}} карактери долга." + }, + "ID": "ID", + "EMAIL": "E-пошта", + "PHONE": "Телефонски број", + "PHONEEMPTY": "Нема дефиниран телефонски број", + "PHONEVERIFIED": "Телефонскиот број е верифициран.", + "EMAILVERIFIED": "Е-поштата е верифицирана", + "NOTVERIFIED": "не е верифицирано", + "PREFERRED_LOGINNAME": "Предпочитано корисничко име", + "ISINITIAL": "Корисникот сè уште не е активен.", + "LOGINMETHODS": { + "TITLE": "Контакт податоци", + "DESCRIPTION": "Внесените податоци се користат за праќање на важни информации, како ресетирање на лозинката преку е-пошта до вас.", + "EMAIL": { + "TITLE": "Е-пошта", + "VALID": "верифицирано", + "ISVERIFIED": "Верифицирана е-пошта", + "ISVERIFIEDDESC": "Доколку е-поштата е обележана како верифицирана, нема да се испрати барање за верификација на е-поштата.", + "RESEND": "Повторно испрати верификација за е-пошта", + "EDITTITLE": "Промени е-пошта", + "EDITDESC": "Внесете ја новата е-пошта во полето подолу." + }, + "PHONE": { + "TITLE": "Телефонски број", + "VALID": "верифицирано", + "RESEND": "Повторно испрати верификација со SMS порака", + "EDITTITLE": "Промени телефонски број", + "EDITVALUE": "Телефонски број", + "EDITDESC": "Внесете го новиот телефонски број во полето подолу.", + "DELETETITLE": "Избриши телефонски број", + "DELETEDESC": "Дали навистина сакате да го избришете телефонскиот број" + }, + "RESENDCODE": "Повторно испрати код", + "ENTERCODE": "Верифицирај", + "ENTERCODE_DESC": "Внесете го кодот за верификација" + }, + "GRANTS": { + "TITLE": "Овластувања за корисникот", + "DESCRIPTION": "Овозможете на овој корисник пристап до одредени проекти", + "CREATE": { + "TITLE": "Креирајте овластување за корисник", + "DESCRIPTION": "Пребарајте ја организацијата, проектот и соодветните улоги на проектот." + }, + "PROJECTNAME": "Име на проектот", + "PROJECT-OWNED": "Проект", + "PROJECT-GRANTED": "Дозволен проект", + "FILTER": { + "0": "филтрирај за корисник", + "1": "филтрирај за домен", + "2": "филтрирај за име на проект", + "3": "филтрирај за име на улога" + } + }, + "STATE": { + "0": "Непознато", + "1": "Активно", + "2": "Неактивно", + "3": "Избришано", + "4": "Заклучено", + "5": "Суспендирано", + "6": "Иницијално" + }, + "SEARCH": { + "ADDITIONAL": "Корисничко име (тековна организација)", + "ADDITIONAL-EXTERNAL": "Корисничко име (надворешна организација)" + }, + "TARGET": { + "SELF": "Доколку сакате да доделите пристап на корисник од друга организација", + "EXTERNAL": "Доделете пристап на корисник од вашата организација", + "CLICKHERE": "кликнете овде" + }, + "SIGNEDOUT": "Одјавени сте. Кликнете на копчето \"Најави се\" за повторна најава.", + "SIGNEDOUT_BTN": "Најави се", + "EDITACCOUNT": "Уреди профил", + "ADDACCOUNT": "Најави се со друга корисничка сметка", + "RESENDINITIALEMAIL": "Повторно испрати е-пошта за активација", + "RESENDEMAILNOTIFICATION": "Повторно испрати е-пошта за известување", + "TOAST": { + "CREATED": "Корисникот е успешно креиран.", + "SAVED": "Профилот е успешно зачуван.", + "USERNAMECHANGED": "Корисничкото име е променето.", + "EMAILSAVED": "Е-поштата е успешно зачувана.", + "INITEMAILSENT": "Активационата е-пошта е испратена.", + "PHONESAVED": "Телефонскиот број е успешно зачуван.", + "PHONEREMOVED": "Телефонскиот број е отстранет.", + "PHONEVERIFIED": "Телефонскиот број е успешно верифициран.", + "PHONEVERIFICATIONSENT": "Испратен е код за верификација на телефонскиот број.", + "EMAILVERIFICATIONSENT": "Испратен е код за верификација на е-поштата.", + "OTPREMOVED": "OTP-от е отстранет.", + "U2FREMOVED": "Факторот е отстранет.", + "PASSWORDLESSREMOVED": "Најава без лозинка е отстранета.", + "INITIALPASSWORDSET": "Иницијалната лозинка е поставена.", + "PASSWORDNOTIFICATIONSENT": "Испратено е известување за промена на лозинка.", + "PASSWORDCHANGED": "Лозинката е успешно променета.", + "REACTIVATED": "Корисникот е реактивиран.", + "DEACTIVATED": "Корисникот е деактивиран.", + "SELECTEDREACTIVATED": "Избраните корисници се реактивирани.", + "SELECTEDDEACTIVATED": "Избраните корисници се деактивирани.", + "SELECTEDKEYSDELETED": "Избраните клучеви се избришани.", + "KEYADDED": "Клучот е додаден!", + "MACHINEADDED": "Сервисниот корисник е креиран!", + "DELETED": "Корисникот е успешно избришан!", + "UNLOCKED": "Корисникот е успешно отклучен!", + "PASSWORDLESSREGISTRATIONSENT": "Линкот за регистрација е успешно испратен.", + "SECRETGENERATED": "Тајната е успешно генерирана!", + "SECRETREMOVED": "Тајната е успешно отстранета!" + }, + "MEMBERSHIPS": { + "TITLE": "Улоги на ZITADEL менаџер", + "DESCRIPTION": "Овие се сите овластувања за членување на корисникот. Истите може да ги менувате и на страните за детали за организација, проект или IAM.", + "ORGCONTEXT": "Ги гледате сите организации и проекти поврзани со тековно избраната организација.", + "USERCONTEXT": "Ги гледате сите организации и проекти до кои имате овластување, вклучувајќи и други организации.", + "CREATIONDATE": "Датум на креирање", + "CHANGEDATE": "Последна промена", + "DISPLAYNAME": "Име за приказ", + "REMOVE": "Отстрани", + "TYPE": "Тип", + "ORGID": "ID на организација", + "UPDATED": "Членството е ажурирано.", + "NOPERMISSIONTOEDIT": "Ви недостигаат потребните овластувања за промена на улоги!", + "TYPES": { + "UNKNOWN": "Непознато", + "ORG": "Организација", + "PROJECT": "Проект", + "GRANTEDPROJECT": "Дозволен проект" + } + }, + "PERSONALACCESSTOKEN": { + "ID": "ID", + "TOKEN": "Токен", + "ADD": { + "TITLE": "Генерирај нов токен за личен пристап", + "DESCRIPTION": "Дефинирајте истекување за токенот.", + "CHOOSEEXPIRY": "Изберете датум на истекување", + "CHOOSEDATEAFTER": "Внесете валиден датум на истекување по" + }, + "ADDED": { + "TITLE": "Токен за личен пристап", + "DESCRIPTION": "Копирајте гои зачувајте го вашиот токен за личен пристап. Нема да можете да го видите повторно!" + }, + "DELETE": { + "TITLE": "Избриши токен", + "DESCRIPTION": "Дали сте сигурни дека сакате да го избришете токенот за личен пристап?" + }, + "DELETED": "Токенот е успешно избришан." + } + }, + "METADATA": { + "TITLE": "Метаподатоци", + "DESCRIPTION": "", + "KEY": "Клуч", + "VALUE": "Вредност", + "ADD": "Нов внес", + "SAVE": "Зачувај", + "EMPTY": "Нема метаподатоци", + "SETSUCCESS": "Елементот е успешно зачуван", + "REMOVESUCCESS": "Елементот е успешно избришан" + }, + "FLOWS": { + "TITLE": "Акции и Flows", + "DESCRIPTION": "Дефинирајте скрипти за извршување при одреден тригер.", + "ACTIONSTITLE": "Акции", + "ACTIONSDESCRIPTION": "Овие се вашите скрипти кои можете да ги извршите во flows.", + "FLOWSTITLE": "Flows", + "FLOWSDESCRIPTION": "Flows од одреден тип извршуваат дејности во моментот на тригерот.", + "ID": "ID", + "NAME": "Име", + "STATE": "Статус", + "STATES": { + "0": "нема статус", + "1": "неактивен", + "2": "активен" + }, + "ADDTRIGGER": "Додади тригер", + "FLOWCHANGED": "Flow е успешно променет", + "FLOWCLEARED": "Flow е успешно ресетиран", + "TIMEOUT": "Временски лимит", + "TIMEOUTINSEC": "Временски лимит во секунди", + "ALLOWEDTOFAIL": "Дозволено да не успее", + "SCRIPT": "Скрипта", + "FLOWTYPE": "Тип на Flow", + "TRIGGERTYPE": "Тип на тригер", + "ACTIONS": "Акции", + "ACTIONSMAX": "Според вашиот Tier, имате достапни ограничен број на акции ({{value}}). Проверете дали сте ги оневозможиле оние што не ви се потребни или размислете за надградба на вашиот Tier.", + "DIALOG": { + "ADD": { + "TITLE": "Креирај акција" + }, + "UPDATE": { + "TITLE": "Ажурирај акција" + }, + "DELETEACTION": { + "TITLE": "Избриши акција?", + "DESCRIPTION": "Дали сте сигурни дека сакате да ја избришете акцијата? Ова не може да се врати. Дали сте сигурни?", + "DELETE_SUCCESS": "Акцијага е успешно избришана." + }, + "CLEAR": { + "TITLE": "Ресетирај Flow?", + "DESCRIPTION": "Дали сте сигурни дека сакате да го ресетирате Flow заедно со неговите тригери и акции? Оваа промена не може да се врати. Дали сте сигурни?" + }, + "REMOVEACTIONSLIST": { + "TITLE": "Избриши ги избраните акции?", + "DESCRIPTION": "Дали сте сигурни дека сакате да ги избришете избраните акции од Flow?" + } + }, + "TOAST": { + "ACTIONSSET": "Акциите се поставени", + "ACTIONREACTIVATED": "Акциите се успешно реактивирани", + "ACTIONDEACTIVATED": "Акциите се успешно оневозможени" + } + }, + "IAM": { + "TITLE": "Инстанца", + "DESCRIPTION": "Управувајте со подесувањата на вашата инстанца и организациите", + "POLICIES": { + "TITLE": "Системски политики и подесувања за пристап", + "DESCRIPTION": "Управувајте со глобалните политики и подесувањата за пристап до управување." + }, + "EVENTSTORE": { + "TITLE": "Управување со складиштето на IAM", + "DESCRIPTION": "Управувајте со прегледите на ZITADEL и неуспешните настани." + }, + "MEMBER": { + "TITLE": "Менаџери", + "DESCRIPTION": "Овие менаџери имаат дозвола да направат промени во вашата инстанца." + }, + "PAGES": { + "STATE": "Статус", + "DOMAINLIST": "Домени" + }, + "STATE": { + "0": "Ненаведено", + "1": "Креирање", + "2": "Во тек", + "3": "Стопирање", + "4": "Сопрено" + }, + "VIEWS": { + "TITLE": "Прегледи", + "DESCRIPTION": "Оваа картичка ги прикажува вашите ZITADEL прегледи.", + "VIEWNAME": "Име", + "DATABASE": "База на податоци", + "SEQUENCE": "Секвенца", + "EVENTTIMESTAMP": "Временска ознака", + "LASTSPOOL": "Успешен spool", + "ACTIONS": "Акцији", + "CLEAR": "Исчисти", + "CLEARED": "Прегледот е успешно исчистен!", + "DIALOG": { + "VIEW_CLEAR_TITLE": "Исчисти преглед", + "VIEW_CLEAR_DESCRIPTION": "Дали сте сигурни дека сакате да го исчистите прегледот? Чистењето на прегледот создава процес за време на кој податоците може да не бидат достапни за крајните корисници. Дали сте сигурни?" + } + }, + "FAILEDEVENTS": { + "TITLE": "Неуспешни настани", + "DESCRIPTION": "Оваа картичка ги прикажува вашите неуспешни настани.", + "VIEWNAME": "Име", + "DATABASE": "База на податоци", + "FAILEDSEQUENCE": "Неуспешна секвенца", + "FAILURECOUNT": "Број на неуспешности", + "LASTFAILED": "Последно неуспешен на", + "ERRORMESSAGE": "Порака за грешка", + "ACTIONS": "Акции", + "DELETE": "Отстрани", + "DELETESUCCESS": "Неуспешните настани се отстранети." + }, + "EVENTS": { + "TITLE": "Настани", + "DESCRIPTION": "Овој преглед ги прикажува сите настани.", + "EDITOR": "Уредник", + "EDITORID": "ID на уредник", + "AGGREGATE": "Агрегација", + "AGGREGATEID": "ID на агрегација", + "AGGREGATETYPE": "Тип на агрегација", + "RESOURCEOWNER": "Сопственик на ресурсот", + "SEQUENCE": "Секвенца", + "CREATIONDATE": "Креирано на", + "TYPE": "Тип", + "PAYLOAD": "Податоци", + "FILTERS": { + "BTN": "Филтер", + "USER": { + "IDLABEL": "ID", + "CHECKBOX": "Филтер според уредникот" + }, + "AGGREGATE": { + "TYPELABEL": "Тип на агрегација", + "IDLABEL": "ID", + "CHECKBOX": "Филтер според агрегација" + }, + "TYPE": { + "TYPELABEL": "Тип", + "CHECKBOX": "Филтер според типот" + }, + "RESOURCEOWNER": { + "LABEL": "ID", + "CHECKBOX": "Филтер според сопственикот на ресурсот" + }, + "SEQUENCE": { + "LABEL": "Секвенца", + "CHECKBOX": "Филтер според секвенцата", + "SORT": "Сортирање", + "ASC": "Растечки", + "DESC": "Опаѓачки" + }, + "CREATIONDATE": { + "LABEL": "Датум на креирање", + "CHECKBOX": "Филтер според датумот на креирање" + }, + "OTHER": "друго", + "OTHERS": "други" + }, + "DIALOG": { + "TITLE": "Детали за настанот" + } + }, + "TOAST": { + "MEMBERREMOVED": "Менаџерот е отстранет.", + "MEMBERSADDED": "Менаџерите се додадени.", + "MEMBERADDED": "Менаџерот е додаден.", + "MEMBERCHANGED": "Менаџерот е променет.", + "ROLEREMOVED": "Улогата е отстранета.", + "ROLECHANGED": "Улогата е променета.", + "REACTIVATED": "Реактивиран", + "DEACTIVATED": "Деактивиран" + } + }, + "ORG": { + "PAGES": { + "NAME": "Име", + "ID": "ID", + "CREATIONDATE": "Датум на креирање", + "DATECHANGED": "Променето", + "FILTER": "Филтер", + "FILTERPLACEHOLDER": "Филтер за име", + "LIST": "Организации", + "LISTDESCRIPTION": "Изберете организација.", + "ACTIVE": "Активна", + "CREATE": "Креирај организација", + "DEACTIVATE": "Деактивирај организација", + "REACTIVATE": "Реактивирај организација", + "NOPERMISSION": "Нематеовластувања за пристап до подесување на организацијата.", + "USERSELFACCOUNT": "Користете ја вашата лична корисничка сметка како сопственик на организацијата", + "ORGDETAIL_TITLE": "Внесете го името и доменот на вашата нова организација.", + "ORGDETAIL_TITLE_WITHOUT_DOMAIN": "Внесете го името на вашата нова организација.", + "ORGDETAILUSER_TITLE": "Конфигурирајте го сопственикот на организацијата", + "DELETE": "Избриши организација", + "DEFAULTLABEL": "Стандардна", + "SETASDEFAULT": "Постави како стандардна организација", + "DEFAULTORGSET": "Стандардната организација е успешно променета", + "RENAME": { + "ACTION": "Преименувај", + "TITLE": "Преименувај организација", + "DESCRIPTION": "Внесете го новото име за вашата организација", + "BTN": "Преименувај" + }, + "ORGDOMAIN": { + "TITLE": "Потврда за сопственост на доменот на организацијата", + "VERIFICATION": "За да ја потврдите сопственоста на вашиот домен, треба да преземете датотека за потврда и да ја прикачите на препратената URL адреса наведена подолу, или да поставите запис на DNS (TXT Record) за препратената URL адреса. За да завршите, кликнете на копчето за верификација.", + "VERIFICATION_SKIP": "Можете да ја прескокнете верификацијата за сега и да продолжите со креирањето на вашата организација, но за да ја користите вашата организација, овој чекор треба да се заврши!", + "VERIFICATION_VALIDATION_DESC": "Токените редовно се проверуваат за да се осигура дека сѐ уште сте сопственик на доменот.", + "VERIFICATION_NEWTOKEN_TITLE": "Побарај нов токен", + "VERIFICATION_NEWTOKEN_DESC": "Ако сакате да побарате нов токен, изберете ја вашата посакувана метода. Ако сакате да валидирате веќе постоечки токен, кликнете на копчето погоре.", + "VERIFICATION_VALIDATION_ONGOING": "Веќе е баран верификациски токен. Кликнете на копчето за да покренете проверка на верификацијата.", + "VERIFICATION_VALIDATION_ONGOING_TYPE": "Тип на токенот:", + "VERIFICATION_SUCCESSFUL": "Доменот е успешно верифициран!", + "REQUESTNEWTOKEN": "Побарај нов токен", + "TYPES": { + "1": "HTTP", + "2": "DNS" + } + }, + "DOWNLOAD_FILE": "Преземи датотека", + "SELECTORGTOOLTIP": "Изберете ја оваа организација.", + "PRIMARYDOMAIN": "Основен домен", + "STATE": "Статус", + "USEPASSWORD": "Постави почетна лозинка", + "USEPASSWORDDESC": "Корисникот не мора да постави лозинката при иницијализација." + }, + "LIST": { + "TITLE": "Организации", + "DESCRIPTION": "Овие се организациите на вашата инстанца" + }, + "DOMAINS": { + "NEW": "Додади домен", + "TITLE": "Домени", + "DESCRIPTION": "Конфигурирајте ги вашите домени. Овој домен може да се користи за најава на вашите корисници.", + "SETPRIMARY": "Постави како основен", + "DELETE": { + "TITLE": "Избриши домен", + "DESCRIPTION": "Се подготвувате да го избришете вашиот домен. Имајте предвид дека вашите корисници повеќе нема да можат да го користат овој домен за најава." + }, + "ADD": { + "TITLE": "Додади домен", + "DESCRIPTION": "Се подготвувате да додадете домен за вашата организација. По успешна процедура, вашите корисници ќе можат да го користат доменот за најава." + } + }, + "STATE": { + "0": "Ненаведено", + "1": "Активна", + "2": "Неактивна", + "3": "Избришана" + }, + "MEMBER": { + "TITLE": "Менаџери на организацијата", + "DESCRIPTION": "Дефинирајте ги корисниците кои можат да ги менуваат преференците на вашата организација." + }, + "TOAST": { + "UPDATED": "Организацијата е успешно ажурирана.", + "DEACTIVATED": "Организацијата е деактивирана.", + "REACTIVATED": "Организацијата е реактивирана", + "DOMAINADDED": "Додаден домен.", + "DOMAINREMOVED": "Отстранет домен.", + "MEMBERADDED": "Додаден менаџер.", + "MEMBERREMOVED": "Отстранет менаџер.", + "MEMBERCHANGED": "Променет менаџер.", + "SETPRIMARY": "Поставен основен домен.", + "DELETED": "Организацијата успешно избришана", + "ORG_WAS_DELETED": "Организацијата е избришана." + }, + "DIALOG": { + "DEACTIVATE": { + "TITLE": "Деактивирај организација", + "DESCRIPTION": "Се подготвувате да ја деактивирате вашата организација. Корисниците повеќе нема да можат да се најават. Дали сте сигурни дека сакате да продолжите?" + }, + "REACTIVATE": { + "TITLE": "Реактивирај организација", + "DESCRIPTION": "Се подготвувате да ја реактивирате вашата организација. Корисниците повторно ќе можат да се најават. Дали сте сигурни дека сакате да продолжите?" + }, + "DELETE": { + "TITLE": "Избриши организација", + "DESCRIPTION": "Се подготвувате да ја избришете вашата организација. Ова ќе започне процес со кој што сите податоци поврзани со организацијата ќе бидат избришани. Оваа промена не може да се врати.", + "TYPENAME": "Внесете '{{value}}' за да ја избришете вашата организација.", + "ORGNAME": "Име", + "BTN": "Избриши" + } + } + }, + "SETTINGS": { + "INSTANCE": { + "TITLE": "Подесувања за инстанца", + "DESCRIPTION": "Овие подесувања ќе се применуваат на сите ваши организации, освен ако не се пребришани." + }, + "ORG": { + "TITLE": "Подесувања за организација", + "DESCRIPTION": "Овие подесувања ги прошируваат и препишуваат подесувањата на вашата инстанца." + }, + "LIST": { + "GENERAL": "Генерални", + "LOGIN": "Правила и безбедност при најава", + "LOCKOUT": "Забрана на пристап", + "COMPLEXITY": "Сложеност на лозинката", + "NOTIFICATIONS": "Подесувања за известувања", + "NOTIFICATIONS_DESC": "Подесувања за SMTP и SMS", + "MESSAGETEXTS": "Текстови на пораки", + "IDP": "Identity Providers", + "DOMAIN": "Подесувања за домен", + "LOGINTEXTS": "Текстови на интерфејс за најава", + "BRANDING": "Брендирање", + "PRIVACYPOLICY": "Политика за приватност", + "OIDC": "OIDC времетраење и истекување на токени", + "SECRETS": "Изглед на тајни", + "SECURITY": "Подесувања за безбедност" + }, + "GROUPS": { + "NOTIFICATIONS": "Известувања", + "LOGIN": "Најава и пристап", + "DOMAIN": "Домен", + "TEXTS": "Текстови и јазици", + "APPEARANCE": "Изглед", + "OTHER": "Друго" + } + }, + "SETTING": { + "DEFAULTLANGUAGE": "Стандарден јазик", + "LANGUAGE": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "pl": "Polski", + "zh": "简体中文", + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" + }, + "SMTP": { + "TITLE": "SMTP подесувања", + "SENDERADDRESS": "Адреса на испраќачот", + "SENDERNAME": "Име на испраќачот", + "HOSTANDPORT": "Host и Port", + "USER": "Корисник", + "PASSWORD": "Лозинка", + "SETPASSWORD": "Постави SMTP лозинка", + "PASSWORDSET": "SMTP лозинката е успешно поставена.", + "TLS": "Transport Layer Security (TLS)", + "SAVED": "Успешно зачувано!", + "REQUIREDWARN": "За да испраќате известувања од вашиот домен, мора да ги внесете вашите SMTP податоци." + }, + "SMS": { + "TITLE": "SMS подесувања", + "PROVIDERS": "Провајдери", + "PROVIDER": "SMS провајдер", + "ADDPROVIDER": "Додади SMS провајдер", + "ADDPROVIDERDESCRIPTION": "Изберете еден од достапните провајдери и внесете ги потребните податоци.", + "REMOVEPROVIDER": "Отстрани провајдер", + "REMOVEPROVIDER_DESC": "Се подготвувате да го избришете конфигурацијата на провајдерот. Дали сакате да продолжите?", + "SMSPROVIDERSTATE": { + "0": "Ненаведено", + "1": "Активно", + "2": "Неактивно" + }, + "ACTIVATED": "Провајдерот е активиран.", + "DEACTIVATED": "Провајдерот е деактивиран.", + "TWILIO": { + "SID": "Sid", + "TOKEN": "Токен", + "SENDERNUMBER": "Број на испраќач", + "ADDED": "Twilio e успешно додаден.", + "REMOVED": "Twilio отстранет", + "CHANGETOKEN": "Смени токен", + "SETTOKEN": "Постави токен", + "TOKENSET": "Токенот е успешно поставен." + } + }, + "OIDC": { + "TITLE": "OIDC подесувања", + "ACCESSTOKENLIFETIME": "Времетраење на токенот за пристап", + "IDTOKENLIFETIME": "Времетраење на ID токенот", + "REFRESHTOKENEXPIRATION": "Истекување на токенот за освежување", + "REFRESHTOKENIDLEEXPIRATION": "Истекување на неактивниот токен за освежување", + "INHOURS": "часа", + "INDAYS": "дена" + }, + "SECRETS": { + "TITLE": "Изглед на тајни", + "TYPES": "Типови на тајни", + "TYPE": { + "1": "Иницијализациона е-пошта", + "2": "Е-пошта за верификација", + "3": "Телефонска верификација", + "4": "Промена на лозинка", + "5": "Иницијализација на најава без лозинка", + "6": "Апликациска тајна" + }, + "ADDGENERATOR": "Дефинирајте изглед на тајна", + "GENERATORTYPE": "Тип", + "EXPIRY": "Истекување (во часови)", + "INCLUDEDIGITS": "Вклучи цифри", + "INCLUDESYMBOLS": "Вклучи симболи", + "INCLUDELOWERLETTERS": "Вклучи мали букви", + "INCLUDEUPPERLETTERS": "Вклучи големи букви", + "LENGTH": "Должина", + "UPDATED": "Подесувањата се успешно ажурирани." + }, + "SECURITY": { + "DESCRIPTION": "Ова подесување поставува CSP за дозволување на фрејминг од одредени дозволени домени. Имајте предвид дека овозможувањето на употребата на iFrame-ови може да ви изложи на ризик од clickjacking.", + "IFRAMEENABLED": "Овозможи iFrame", + "ALLOWEDORIGINS": "Дозволени URLs" + }, + "DIALOG": { + "RESET": { + "DEFAULTTITLE": "Ресетирање на подесувањата", + "DEFAULTDESCRIPTION": "Се подготвувате да ги ресетирате вашите подесувања на стандардната конфигурација на вашата инстанца. Дали сте сигурни дека сакате да продолжите?", + "LOGINPOLICY_DESCRIPTION": "Предупредување: Ако продолжите, подесувањата за IDP ќе бидат ресетирани според подесувањата на инстанцата." + } + } + }, + "POLICY": { + "TITLE": "Истражете ги подесувањата", + "DESCRIPTION": "Групирани подесувања кои ја зголемуваат вашата безбедност.", + "APPLIEDTO": "Применето на", + "PWD_COMPLEXITY": { + "TITLE": "Сложеност на лозинката", + "DESCRIPTION": "Осигурува дека сите поставени лозинки одговараат на одреден модел", + "SYMBOLANDNUMBERERROR": "Мора да се состои од цифра и симбол/ознака за интерпункција.", + "SYMBOLERROR": "Мора да содржи симбол/ознака за интерпункција.", + "NUMBERERROR": "Мора да содржи цифра.", + "PATTERNERROR": "Лозинката не соодветствува на бараниот модел." + }, + "NOTIFICATION": { + "TITLE": "Известување", + "DESCRIPTION": "Одредува на кои промени ќе се испраќаат известувања.", + "PASSWORDCHANGE": "Промена на лозинка" + }, + "PRIVATELABELING": { + "TITLE": "Брендирање", + "DESCRIPTION": "Додадете личен стил на најавата и модифицирајте ги правилата за најава.", + "PREVIEW_DESCRIPTION": "Промените во политиката автоматски се активираат на preview околина.", + "BTN": "Изберете датотека", + "ACTIVATEPREVIEW": "Аплицирај конфигурација", + "DARK": "Темен режим", + "LIGHT": "Светол режим", + "CHANGEVIEW": "Смени изглед", + "ACTIVATED": "Промените во политиката сега се ВО ЖИВО", + "THEME": "Тема", + "COLORS": "Бои", + "FONT": "Фонт", + "ADVANCEDBEHAVIOR": "Напредни можности", + "DROP": "Поставете ја сликата тука или", + "RELEASE": "Ослободи", + "DROPFONT": "Поставете ја фонт датотеката тука", + "RELEASEFONT": "Ослободи", + "USEOFLOGO": "Вашето лого ќе се користи на најавата, како и во е-пошти, додека иконата се користи за помали елементи на корисничкиот интерфејс, како префрлачот за организации во конзолата", + "MAXSIZE": "Максималната големина е ограничена на 524kB", + "EMAILNOSVG": "Форматот на датотеката SVG не е поддржан во е-поштите. Затоа поставете го вашето лого во PNG или друг формат кој е поддржан.", + "MAXSIZEEXCEEDED": "Превишена е максималната големина од 524kB.", + "NOSVGSUPPORTED": "Форматот SVG не е поддржан!", + "FONTINLOGINONLY": "Фонтот моментално е прикажан само во интерфејсот за најава.", + "BACKGROUNDCOLOR": "Боја на позадина", + "PRIMARYCOLOR": "Основна боја", + "WARNCOLOR": "Боја на предупредување", + "FONTCOLOR": "Боја на фонтот", + "VIEWS": { + "PREVIEW": "Преглед", + "CURRENT": "Тековна конфигурација" + }, + "PREVIEW": { + "TITLE": "Најава", + "SECOND": "најавете се со вашиот ZITADEL-Aкаунт.", + "ERROR": "Корисникот не е пронајден!", + "PRIMARYBUTTON": "следно", + "SECONDARYBUTTON": "регистрирај се" + } + }, + "PWD_AGE": { + "TITLE": "Важност на лозинка", + "DESCRIPTION": "Можете да поставите политика за истекување на лозинките. Оваа политика издава предупредување откако ќе помени одреденото време на истекување." + }, + "PWD_LOCKOUT": { + "TITLE": "Политика за забрана на пристап", + "DESCRIPTION": "Поставете максимален број на неуспешни обиди за внес на лозинка, по кои корисничките сметки ќе бидат блокирани." + }, + "DOMAIN_POLICY": { + "TITLE": "Подесувања за доменот" + }, + "PRIVATELABELING_POLICY": { + "TITLE": "Брендирање", + "BTN": "Изберете датотека", + "DESCRIPTION": "Прилагодете го изгледот на најавата", + "ACTIVATEPREVIEW": "Активирај конфигурација" + }, + "LOGIN_POLICY": { + "TITLE": "Подесувања за најава", + "DESCRIPTION": "Дефинирајте како корисниците можат да се автентицираат и конфигурирајте Identity Providers", + "DESCRIPTIONCREATEADMIN": "Корисниците можат да избираат од достапните IDPs подолу.", + "DESCRIPTIONCREATEMGMT": "Корисниците можат да избираат од достапните IDPs подолу. Забелешка: Можете да користите системски поставени IDPs, како и IDPs поставени само за вашата организација.", + "ADVANCED": "Напредно", + "LIFETIMEDURATIONS": "Време на траење на најавата", + "SAVED": "Успешно зачувано!" + }, + "PRIVACY_POLICY": { + "TITLE": "Политика за приватност и Услови за користење", + "DESCRIPTION": "Поставете линкови кон вашите Политика за приватност и Услови за користење", + "TOSLINK": "Линк кон Условите за користење", + "POLICYLINK": "Линк кон Политиката за приватност", + "HELPLINK": "Линк кон Помош", + "SUPPORTEMAIL": "Е-пошта за поддршка", + "SAVED": "Успешно зачувано!", + "RESET_TITLE": "Врати на стандардни вредности", + "RESET_DESCRIPTION": "Се подготвувате да ги вратите стандардните линкови за Условите за користење и Политиката за приватност. Дали сте сигурни дека сакате да продолжите?" + }, + "LOGIN_TEXTS": { + "TITLE": "Текстови на интерфејсот за најава", + "DESCRIPTION": "Дефинирајте ги вашите текстови за интерфејсите за најава. Ако текстовите се празни, ќе се користи стандардната вредност.", + "DESCRIPTION_SHORT": "Дефинирајте ги вашите текстови за интерфејсите за најава.", + "NEWERVERSIONEXISTS": "Постои понова верзија", + "CURRENTDATE": "Тековна конфигурација", + "CHANGEDATE": "Понова верзија од", + "KEYNAME": "Екран / интерфејс за најава", + "RESET_TITLE": "Врати на стандардни вредности", + "RESET_DESCRIPTION": "Се подготвувате да ги вратите сите стандардни вредности. Сите промени што ги направивте ќе бидат трајно избришани. Дали сте сигурни дека сакате да продолжите?", + "UNSAVED_TITLE": "Дали сакате да продолжите без зачувување?", + "UNSAVED_DESCRIPTION": "Имате направено промени без зачувување. Дали сакате да ги зачувате сега?", + "LOCALE": "Locale Code", + "LOCALES": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "pl": "Polski", + "zh": "简体中文", + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" + }, + "KEYS": { + "emailVerificationDoneText": "Е-поштата е верифицирана", + "emailVerificationText": "Верификација на е-пошта", + "externalUserNotFoundText": "Надворешниот корисник не е пронајден", + "footerText": "Футер", + "initMfaDoneText": "Иницијализацијата на MFA е завршена", + "initMfaOtpText": "Иницијализација на MFA", + "initMfaPromptText": "Иницијализација на MFA (Prompt)", + "initMfaU2fText": "Иницијализација на Universal Second Factor", + "initPasswordDoneText": "Иницијализацијата на лозинката е завршена", + "initPasswordText": "Иницијализација на лозинка", + "initializeDoneText": "Иницијализацијата на корисникот е завршена", + "initializeUserText": "Иницијализација на корисник", + "linkingUserDoneText": "Поврзувањето на корисникот е завршено", + "loginText": "Најава", + "logoutText": "Одјава", + "mfaProvidersText": "MFA провајдери", + "passwordChangeDoneText": "Промената на лозинката е завршена", + "passwordChangeText": "Промена на лозинка", + "passwordResetDoneText": "Ресетирањето на лозинката е завршено", + "passwordText": "Лозинка", + "registrationOptionText": "Опции за регистрација", + "registrationOrgText": "Регистрирај организација", + "registrationUserText": "Регистрирај корисник", + "selectAccountText": "Избери корисничка сметка", + "successLoginText": "Најавата е успешна", + "usernameChangeDoneText": "Завршена е промената на корисничкото име", + "usernameChangeText": "Промена на корисничкото име", + "verifyMfaOtpText": "Верификација на OTP", + "verifyMfaU2fText": "Верификација на Universal Second Factor", + "passwordlessPromptText": "Најава без лозинка (Prompt)", + "passwordlessRegistrationDoneText": "Регистрацијата за лозинка без најава завршена", + "passwordlessRegistrationText": "Регистрација за лозинка без најава", + "passwordlessText": "Најава без лозинка", + "externalRegistrationUserOverviewText": "Преглед на надворешно регистрирани корисници" + } + }, + "MESSAGE_TEXTS": { + "TITLE": "Текстови на пораки", + "DESCRIPTION": "Дефинирајте ги текстовите за вашите известувања по е-пошта.", + "TYPE": "Известување", + "TYPES": { + "INIT": "Иницијализација", + "VE": "Верификација на е-пошта", + "VP": "Верификација на телефонски број", + "PR": "Ресетирање на лозинка", + "DC": "Зафатница на домен", + "PL": "Лозинка без лозинка", + "PC": "Промена на лозинка" + }, + "CHIPS": { + "firstname": "Име", + "lastname": "Презиме", + "code": "Код", + "preferredLoginName": "Посакувано корисничко име", + "displayName": "Име за приказ", + "nickName": "Прекар", + "loginnames": "Кориснички имиња", + "domain": "Домен", + "lastEmail": "Последна е-пошта", + "lastPhone": "Последен телефонски број", + "verifiedEmail": "Верифицирана е-пошта", + "verifiedPhone": "Верифициран телефонски број", + "changedate": "Датум на промена", + "username": "Корисничко име", + "tempUsername": "Привремено корисничко име" + }, + "TOAST": { + "UPDATED": "Прилагодените текстови се зачувани." + } + }, + "DEFAULTLABEL": "Моменталните подесувања одговараат на стандардите на вашата инстанца.", + "BTN_INSTALL": "Подеси", + "BTN_EDIT": "Промени", + "DATA": { + "DESCRIPTION": "Опис", + "MINLENGTH": "минимална должина", + "HASNUMBER": "има бројка", + "HASSYMBOL": "има симбол", + "HASLOWERCASE": "има мали букви", + "HASUPPERCASE": "има големи букви", + "SHOWLOCKOUTFAILURES": "прикажи неуспешни заклучувања", + "MAXATTEMPTS": "Максимален број на обиди за лозинка", + "EXPIREWARNDAYS": "Предупредување за истекување по ден", + "MAXAGEDAYS": "Максимална возраст во денови", + "USERLOGINMUSTBEDOMAIN": "Додади организациски домен како суфикс на корисничките имиња", + "USERLOGINMUSTBEDOMAIN_DESCRIPTION": "Ако го овозможите ова подесување, сите кориснички имиња ќе имаат суфикс на организацискиот домен. Доколку ова подесување е оневозможено, морате да се осигурате дека корисничките имиња се уникатни низ сите организации.", + "VALIDATEORGDOMAINS": "Валидирај организациски домени", + "SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP адресата на испраќачот се поклопува со доменот на инстанцата", + "ALLOWUSERNAMEPASSWORD": "Дозволено корисничко име и лозинка", + "ALLOWEXTERNALIDP": "Дозволен надворешен IDP", + "ALLOWREGISTER": "Дозволена регистрација", + "ALLOWUSERNAMEPASSWORD_DESC": "Дозволена е конвенционална најава со корисничко име и лозинка.", + "ALLOWEXTERNALIDP_DESC": "Најавата е дозволена за поддржуваните IDPs", + "ALLOWREGISTER_DESC": "Доколку е избрана опцијата, се прикажува дополнителен чекор за регистрирање на корисник во најавата.", + "FORCEMFA": "Задолжителна MFA", + "FORCEMFA_DESC": "Доколку е избрана опцијата, корисниците мораат да конфигурираат втор фактор за најава.", + "FORCEMFALOCALONLY": "Force MFA за локални корисници", + "FORCEMFALOCALONLY_DESC": "Ако е избрана опцијата, локалните автентицирани корисници треба да конфигурираат втор фактор за најавување.", + "HIDEPASSWORDRESET": "Сокриј го ресетирањето на лозинка", + "HIDEPASSWORDRESET_DESC": "Доколку е избрана опцијата, корисникот нема да може да ја ресетира својата лозинка во процесот на најава.", + "HIDELOGINNAMESUFFIX": "Сокриј го суфиксот на корисничкото име", + "HIDELOGINNAMESUFFIX_DESC": "Сокриј го суфиксот на корисничкото име во интерфејсот за најава", + "IGNOREUNKNOWNUSERNAMES": "Занемари непознати кориснички имиња", + "IGNOREUNKNOWNUSERNAMES_DESC": "Доколку е избрана опцијата, екранот за лозинка ќе се прикаже во процесот на најава, дури и ако корисникот не бил пронајден. Грешката при проверката на лозинката нема да открие дали корисничкото име или лозинката се погрешни.", + "ALLOWDOMAINDISCOVERY": "Дозволи откривање на домени", + "ALLOWDOMAINDISCOVERY_DESC": "Доколку е избрана опцијата, суфиксот (@domain.com) на непознатото корисничко име внесено на екранот за најава ќе биде спореден со организациските домени и при успех ќе пренасочи кон регистрацијата на таа организација.", + "DISABLELOGINWITHEMAIL": "Оневозможи најава со е-пошта", + "DISABLELOGINWITHPHONE": "Оневозможи најава со телефонски број", + "DEFAULTREDIRECTURI": "Стандардно Redirect URI", + "DEFAULTREDIRECTURI_DESC": "Дефинира каде корисникот ќе биде пренасочен ако најавата започне без контекст на апликација (на пример, од е-пошта)", + "ERRORMSGPOPUP": "Прикажи грешка во дијалог", + "DISABLEWATERMARK": "Сокриј Watermark", + "DISABLEWATERMARK_DESC": "Сокриј го Powered by ZITADEL watermark во интерфејсот за најава", + "PASSWORDCHECKLIFETIME": "Времетраење на проверката на лозинка", + "EXTERNALLOGINCHECKLIFETIME": "Времетраење на проверката на надворешна најава", + "MFAINITSKIPLIFETIME": "Времетраење на иницијализацијата на Multifactor", + "SECONDFACTORCHECKLIFETIME": "Времетраење на проверката на втор фактор", + "MULTIFACTORCHECKLIFETIME": "Времетраење на проверката на Multifactor", + "INHOURS": "часови" + }, + "RESET": "Ресетирај на стандардните поставки на инстанцата", + "CREATECUSTOM": "Креирај прилагодена политика", + "TOAST": { + "SET": "Политиката е успешно поставена!", + "RESETSUCCESS": "Политиката е успешно ресетирана!", + "UPLOADSUCCESS": "Успешно прикачено!", + "DELETESUCCESS": "Успешно избришано!", + "UPLOADFAILED": "Неуспешно прикачување!" + } + }, + "ORG_DETAIL": { + "TITLE": "Организација", + "DESCRIPTION": "Овде можете да ја уредувате конфигурацијата на вашата организација и да управувате со членовите.", + "DETAIL": { + "TITLE": "Детали", + "NAME": "Име", + "DOMAIN": "Домен", + "STATE": { + "0": "Не е дефинирано", + "1": "Активно", + "2": "Неактивно" + } + }, + "MEMBER": { + "TITLE": "Членови", + "USERNAME": "Корисничко име", + "DISPLAYNAME": "Име за приказ", + "LOGINNAME": "Корисничко име за најава", + "EMAIL": "Е-пошта", + "ROLES": "Улоги", + "ADD": "Додади член", + "ADDDESCRIPTION": "Внесете ги имињата на корисниците кои сакате да ги додадете." + }, + "TABLE": { + "TOTAL": "Вкупно записи", + "SELECTION": "Избрани елементи", + "DEACTIVATE": "Деактивирај корисник", + "ACTIVATE": "Активирај корисник", + "DELETE": "Избриши корисник", + "CLEAR": "Исчисти избор" + } + }, + "PROJECT": { + "PAGES": { + "TITLE": "Проект", + "DESCRIPTION": "Овде можете да дефинирате апликации, да управувате со улоги и да дозволите на други организации да го користат вашиот проект.", + "DELETE": "Избриши проект", + "LIST": "Проекти", + "LISTDESCRIPTION": "Ако не можете да најдете проект, контактирајте го сопственикот на проектот или некого со соодветни права за да добиете пристап до проектот.", + "DETAIL": "Детали", + "CREATE": "Креирај проект", + "CREATE_DESC": "Внесете го името на вашиот проект.", + "ROLE": "Улога", + "NOITEMS": "Нема проекти", + "ZITADELPROJECT": "Ова припаѓа на ZITADEL проектот. Внимание: Ако направите промени, ZITADEL може да не работи како што е предвидено.", + "TYPE": { + "OWNED": "Сопствени проекти", + "GRANTED": "Доделени проекти", + "OWNED_SINGULAR": "Сопствен проект", + "GRANTED_SINGULAR": "Доделен проект" + }, + "PRIVATELABEL": { + "TITLE": "Подесувања за брендирање", + "0": { + "TITLE": "Неспецифицирано", + "DESC": "Откако корисникот ќе биде идентификуван, ќе се прикаже брендирањето на организацијата на идентификуваниот корисник, пред да се прикаже стандардното системско брендирање." + }, + "1": { + "TITLE": "Користи ги подесувањата на проектот", + "DESC": "Ќе се прикаже брендирањето на организацијата која е сопственик на проектот." + }, + "2": { + "TITLE": "Користи ги подесувањата на организацијата на корисникот", + "DESC": "Ќе се прикаже брендирањето на организацијата на проектот, но откако корисникот ќе биде идентификуван, ќе се прикаже подесувањето на организацијата на идентификуваниот корисник." + }, + "DIALOG": { + "TITLE": "Подесувања за брендирање", + "DESCRIPTION": "Изберете го однесувањето на најавата при користење на проектот." + } + }, + "PINNED": "Прикачен", + "ALL": "Сите", + "CREATEDON": "Креиран на", + "LASTMODIFIED": "Последно променет на", + "ADDNEW": "Креирај нов проект", + "DIALOG": { + "REACTIVATE": { + "TITLE": "Реактивирај проект", + "DESCRIPTION": "Дали навистина сакате да го реактивирате вашиот проект?" + }, + "DEACTIVATE": { + "TITLE": "Деактивирај проект", + "DESCRIPTION": "Дали навистина сакате да го деактивирате вашиот проект?" + }, + "DELETE": { + "TITLE": "Избриши проект", + "DESCRIPTION": "Дали навистина сакате да го избришете вашиот проект?", + "TYPENAME": "Напишете го името на проектот за да го избришете перманентно." + } + } + }, + "SETTINGS": { + "TITLE": "Подесувања", + "DESCRIPTION": "" + }, + "STATE": { + "TITLE": "Статус", + "0": "Не е дефинирано", + "1": "Активно", + "2": "Неактивно" + }, + "TYPE": { + "TITLE": "Тип", + "0": "Непознат тип", + "1": "Сопствен", + "2": "Доделен" + }, + "NAME": "Име", + "NAMEDIALOG": { + "TITLE": "Преименувај проект", + "DESCRIPTION": "Внесете го новото име за вашиот проект", + "NAME": "Ново име" + }, + "MEMBER": { + "TITLE": "Менаџери", + "TITLEDESC": "Менаџерите можат да направат промени на овој проект врз основа на нивната улога.", + "DESCRIPTION": "Овие менаџери можеби ќе можат да го уредат вашиот проект.", + "USERNAME": "Корисничко име", + "DISPLAYNAME": "Име за приказ", + "LOGINNAME": "Корисничко име за најава", + "EMAIL": "Е-пошта", + "ROLES": "Улоги", + "USERID": "ID на корисник" + }, + "GRANT": { + "EMPTY": "Нема доделена организација.", + "TITLE": "Доделување на проект", + "DESCRIPTION": "Овозможете на друга организација да го користи вашиот проект.", + "EDITTITLE": "Уреди улоги", + "CREATE": { + "TITLE": "Креирај овластување за организација", + "SEL_USERS": "Изберете ги корисниците на кои сакате да им дозволите пристап", + "SEL_PROJECT": "Пребарајте проект", + "SEL_ROLES": "Изберете ги улогите кои сакате да бидат додадени на овластувањето", + "SEL_USER": "Изберете корисници", + "SEL_ORG": "Подесете го доменот", + "SEL_ORG_DESC": "Внесете го комплетниот домен за да ја специфицирате организацијата на која сакате да и дозволите пристап.", + "ORG_TITLE": "Организација", + "ORG_DESCRIPTION": "Сакате да дозволите пристап на корисник за организацијата {{name}}.", + "ORG_DESCRIPTION_DESC": "Променете го контекстот во header-от погоре за да дозволите пристап на корисник за друга организација.", + "SEL_ORG_FORMFIELD": "Комплетен домен", + "SEL_ORG_BUTTON": "Пребарај организација", + "FOR_ORG": "Овластување е креирано за:" + }, + "DETAIL": { + "TITLE": "Доделување на проект", + "DESC": "Можете да изберете кои улоги може да се користат од специфицираната организација и да изберете менаџери", + "MEMBERTITLE": "Менаџери", + "MEMBERDESC": "Овие се менаџерите на доделената организација. Додадете корисници овде кои треба да добијат пристап за уредување на податоците на проектот.", + "PROJECTNAME": "Име на проект", + "GRANTEDORG": "Доделена организација", + "RESOURCEOWNER": "Сопственик на ресурсот" + }, + "STATE": "Статус", + "STATES": { + "1": "Активно", + "2": "Неактивно" + }, + "ALL": "Сите", + "SHOWDETAIL": "Прикажи детали", + "USER": "Корисник", + "MEMBERS": "Менаџери", + "ORG": "Организација", + "PROJECTNAME": "Име на проект", + "GRANTEDORG": "Доделена организација", + "GRANTEDORGDOMAIN": "Домен", + "RESOURCEOWNER": "Сопственик на ресурсот", + "GRANTEDORGNAME": "Име на организацијата", + "GRANTID": "ID на овластување", + "CREATIONDATE": "Датум на креирање", + "CHANGEDATE": "Последно изменето", + "DATES": "Датуми", + "ROLENAMESLIST": "Улоги", + "NOROLES": "Нема улоги", + "TYPE": "Тип", + "TOAST": { + "PROJECTGRANTUSERGRANTADDED": "Овластувањето за проект е креирано.", + "PROJECTGRANTADDED": "Овластувањето за проект е креирано.", + "PROJECTGRANTCHANGED": "Овластувањето за проект е променето.", + "PROJECTGRANTMEMBERADDED": "Менаџерот за овластувањето е додаден.", + "PROJECTGRANTMEMBERCHANGED": "Менаџерот за овластувањето е променет.", + "PROJECTGRANTMEMBERREMOVED": "Менаџерот за овластувањето е отстранет.", + "PROJECTGRANTUPDATED": "Овластувањето за проект е ажурирано" + }, + "DIALOG": { + "DELETE_TITLE": "Избриши овластување за проект", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете овластувањето на проект?" + }, + "ROLES": "Улоги на проект" + }, + "APP": { + "TITLE": "Апликации", + "NAME": "Име", + "NAMEREQUIRED": "Името е задолжително." + }, + "ROLE": { + "EMPTY": "Сѐ уште не е креирана улога.", + "ADDNEWLINE": "Додај дополнителна улога", + "KEY": "Клуч", + "TITLE": "Улоги", + "DESCRIPTION": "Дефинирајте некои улоги кои можат да се користат за креирање на проектни овластувања.", + "NAME": "Име", + "DISPLAY_NAME": "Име за приказ", + "GROUP": "Група", + "ACTIONS": "Акции", + "ADDTITLE": "Креирај улога", + "ADDDESCRIPTION": "Внесете ги податоците за новата улога.", + "EDITTITLE": "Уреди улога", + "EDITDESCRIPTION": "Внесете ги новите податоци за улогата.", + "DELETE": "Избриши улога", + "CREATIONDATE": "Креирано", + "CHANGEDATE": "Последна промена", + "SELECTGROUPTOOLTIP": "Изберете ги сите улоги од групата {{group}}.", + "OPTIONS": "Опции", + "ASSERTION": "Assert Roles on Authentication", + "ASSERTION_DESCRIPTION": "Информациите за улогите се праќаат од Userinfo endpoint и зависно од подесувањата на апликацијата во токените и другите типови.", + "CHECK": "Проверка на овластување при автентикација", + "CHECK_DESCRIPTION": "Ако е активирано, корисниците имаат дозвола да се автентицираат само доколку им е доделена некоја улога на нивниот профил.", + "DIALOG": { + "DELETE_TITLE": "Избриши улога", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да ја избришете улогата?" + } + }, + "HAS_PROJECT": "Проверка за проект при автентикација", + "HAS_PROJECT_DESCRIPTION": "Се проверува дали организацијата на корисникот го има овој проект. Доколку го нема, корисникот нема да може да се автентицира.", + "TABLE": { + "TOTAL": "Вкупно записи:", + "SELECTION": "Избрани елементи", + "DEACTIVATE": "Деактивирај проект", + "ACTIVATE": "Активирај проект", + "DELETE": "Избриши проект", + "ORGNAME": "Име на организација", + "ORGDOMAIN": "Домен на организација", + "STATE": "Статус", + "TYPE": "Тип", + "CREATIONDATE": "Креиран на", + "CHANGEDATE": "Последна измена", + "RESOURCEOWNER": "Сопственик", + "SHOWTABLE": "Прикажи табела", + "SHOWGRID": "Прикажи грид", + "EMPTY": "Не е пронајден проект" + }, + "TOAST": { + "MEMBERREMOVED": "Менаџерот е отстранет.", + "MEMBERSADDED": "Менаџерите се додадени.", + "MEMBERADDED": "Менаџерот е додаден.", + "MEMBERCHANGED": "Менаџерот е променет.", + "ROLESCREATED": "Улогите се креирани.", + "ROLEREMOVED": "Улогата е отстранета.", + "ROLECHANGED": "Улогата е променета.", + "REACTIVATED": "Реактивирано.", + "DEACTIVATED": "Деактивирано.", + "CREATED": "Проектот е креиран.", + "UPDATED": "Проектот е променет.", + "GRANTUPDATED": "Доделувањето е променето.", + "DELETED": "Проектот е избришан." + } + }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "Избриши улога", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да ја избришете улогата?" + } + }, + "NEXTSTEPS": { + "TITLE": "Следни чекори" + }, + "IDP": { + "LIST": { + "TITLE": "Identity Providers", + "DESCRIPTION": "Управувајте со конфигурацијата на вашите IDPs, кои потоа може да се активираат во вашите подесувања за најавување.", + "ACTIVETITLE": "Активни IDPs" + }, + "CREATE": { + "TITLE": "Додади провајдер", + "DESCRIPTION": "Изберете еден или повеќе од следниве провајдери.", + "STEPPERTITLE": "Креирај провајдер", + "OIDC": { + "TITLE": "OIDC провајдер", + "DESCRIPTION": "Внесете ги потребните податоци за вашиот OIDC провајдер." + }, + "OAUTH": { + "TITLE": "OAuth провајдер", + "DESCRIPTION": "Внесете ги потребните податоци за вашиот OAuth провајдер." + }, + "JWT": { + "TITLE": "JWT провајдер", + "DESCRIPTION": "Внесете ги потребните податоци за вашиот JWT провајдер." + }, + "GOOGLE": { + "TITLE": "Google провајдер", + "DESCRIPTION": "Внесете ги податоците за вашиот Google провајдер на идентитети" + }, + "GITLAB": { + "TITLE": "Gitlab провајдер", + "DESCRIPTION": "Внесете ги податоците за вашиот Gitlab провајдер на идентитети" + }, + "GITLABSELFHOSTED": { + "TITLE": "Gitlab Self Hosted провајдер", + "DESCRIPTION": "Внесете ги податоците за вашиот Gitlab Self Hosted провајдер на идентитети" + }, + "GITHUBES": { + "TITLE": "GitHub Enterprise Server провајдер", + "DESCRIPTION": "Внесете ги податоците за вашиот GitHub Enterprise Server провајдер на идентитети" + }, + "GITHUB": { + "TITLE": "Github провајдер", + "DESCRIPTION": "Внесете ги податоците за вашиот Github провајдер на идентитети" + }, + "AZUREAD": { + "TITLE": "Microsoft провајдер", + "DESCRIPTION": "Внесете ги податоците за вашиот Microsoft провајдер на идентитети" + }, + "LDAP": { + "TITLE": "Active Directory / LDAP", + "DESCRIPTION": "Внесете ги податоците за вашиот LDAP провајдер" + } + }, + "DETAIL": { + "TITLE": "Провајдер на идентитети", + "DESCRIPTION": "Ажурирајте ја конфигурацијата на вашиот провајдер", + "DATECREATED": "Креирано", + "DATECHANGED": "Променето" + }, + "OPTIONS": { + "ISAUTOCREATION": "Автоматско креирање", + "ISAUTOCREATION_DESC": "Доколку е избрано, корисничка сметка ќе биде креиран ако сè уште не постои.", + "ISAUTOUPDATE": "Автоматско ажурирање", + "ISAUTOUPDATE_DESC": "Доколку е избрано, корисничките сметки се ажурираат при повторно најавување.", + "ISCREATIONALLOWED": "Дозволено креирање на кориснички сметки", + "ISCREATIONALLOWED_DESC": "Одредува дали може да се креираат кориснички сметки.", + "ISLINKINGALLOWED": "Дозволено поврзување на кориснички сметки", + "ISLINKINGALLOWED_DESC": "Одредува дали може да се поврзе идентитет со постоечка корисничка сметка." + }, + "OWNERTYPES": { + "0": "непознато", + "1": "Инстанца", + "2": "Организација" + }, + "STATES": { + "1": "активно", + "2": "неактивно" + }, + "AZUREADTENANTTYPES": { + "3": "Tenant ID", + "0": "Заедничко", + "1": "Организации", + "2": "Корисници" + }, + "AZUREADTENANTTYPE": "Tenant Type", + "AZUREADTENANTID": "Tenant ID", + "EMAILVERIFIED": "Е-пошта верифицирана", + "NAMEHINT": "Ако е наведено, ќе биде прикажано во интерфејсот за најавување.", + "OPTIONAL": "незадолжително", + "LDAPATTRIBUTES": "LDAP атрибути", + "UPDATEBINDPASSWORD": "ажурирање на лозинка за поврзување", + "UPDATECLIENTSECRET": "ажурирање на клиентска тајна", + "ADD": "Додај IDP", + "TYPE": "Тип", + "OWNER": "Сопственик", + "ID": "ID", + "NAME": "Име", + "AUTHORIZATIONENDPOINT": "Точка на авторизација", + "TOKENENDPOINT": "Точка на токени", + "USERENDPOINT": "Точка на корисник", + "IDATTRIBUTE": "ID атрибут", + "AVAILABILITY": "Достапност", + "AVAILABLE": "достапно", + "AVAILABLEBUTINACTIVE": "достапно, но неактивно", + "SETAVAILABLE": "постави како достапно", + "SETUNAVAILABLE": "постави како недостапно", + "CONFIG": "Конфигурација", + "STATE": "Статус", + "ISSUER": "Issuer", + "SCOPESLIST": "Листа на опсези", + "CLIENTID": "Client Id", + "CLIENTSECRET": "Клиентска Тајна", + "LDAPCONNECTION": "Конекција", + "LDAPUSERBINDING": "Врска на корисник", + "BASEDN": "BaseDn", + "BINDDN": "BindDn", + "BINDPASSWORD": "Лозинка на поврзување", + "SERVERS": "Сервери", + "STARTTLS": "Start TLS", + "TIMEOUT": "Тајмаут во секунди", + "USERBASE": "База на корисници", + "USERFILTERS": "Филтри за корисник", + "USEROBJECTCLASSES": "Класи на објекти за корисник", + "REQUIRED": "задолжително", + "LDAPIDATTRIBUTE": "ID атрибут за", + "AVATARURLATTRIBUTE": "Аватар URL атрибут", + "DISPLAYNAMEATTRIBUTE": "Атрибут за име за приказ", + "EMAILATTRIBUTEATTRIBUTE": "Атрибут за е-пошта", + "EMAILVERIFIEDATTRIBUTE": "Атрибут за верифицирана е-пошта", + "FIRSTNAMEATTRIBUTE": "Атрибут за име", + "LASTNAMEATTRIBUTE": "Атрибут за презиме", + "NICKNAMEATTRIBUTE": "Атрибут за прекар", + "PHONEATTRIBUTE": "Атрибут за телефонски број", + "PHONEVERIFIEDATTRIBUTE": "Атрибут за верифициран телефонски број", + "PREFERREDLANGUAGEATTRIBUTE": "Атрибут за посакуван јазик", + "PREFERREDUSERNAMEATTRIBUTE": "Атрибут за посакувано корисничко име", + "PROFILEATTRIBUTE": "Атрибут за профил", + "IDPDISPLAYNAMMAPPING": "Мапирање на името за приказ на IDP", + "USERNAMEMAPPING": "Мапирање на корисничкото име", + "DATES": "Датуми", + "CREATIONDATE": "Креирано на", + "CHANGEDATE": "Последно изменето", + "DEACTIVATE": "Деактивирај", + "ACTIVATE": "Активирај", + "DELETE": "Избриши", + "DELETE_TITLE": "Избриши IDP", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете IDP? Промените се неповратни.", + "DELETE_SELECTION_TITLE": "Избриши IDP", + "DELETE_SELECTION_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете IDP? Промените се неповратни.", + "EMPTY": "Нема достапни провајдери на идентитети", + "OIDC": { + "GENERAL": "Општи информации", + "TITLE": "Конфигурација на OIDC", + "DESCRIPTION": "Внесете ги податоците за OIDC IDP." + }, + "JWT": { + "TITLE": "JWT Конфигурација", + "DESCRIPTION": "Внесете ги податоците за JWT IDP.", + "HEADERNAME": "Име на хедер", + "JWTENDPOINT": "JWT Крајна точка", + "JWTKEYSENDPOINT": "JWT Крајна точка за клучеви" + }, + "TOAST": { + "SAVED": "Успешно зачувано.", + "REACTIVATED": "IDP повторно активиран.", + "DEACTIVATED": "IDP деактивиран.", + "SELECTEDREACTIVATED": "Избраните IDPs се повторно активирани.", + "SELECTEDDEACTIVATED": "Избраните IDPs се деактивирани.", + "SELECTEDKEYSDELETED": "Избраните IDPs се избришани.", + "DELETED": "IDP успешно отстранет!", + "ADDED": "Успешно додадено.", + "REMOVED": "Успешно отстрането." + } + }, + "MFA": { + "LIST": { + "MULTIFACTORTITLE": "Без лозинка", + "MULTIFACTORDESCRIPTION": "Дефинирајте ги овде вашите мултифактори за најава без лозинка.", + "SECONDFACTORTITLE": "Мултифактор автентикација", + "SECONDFACTORDESCRIPTION": "Дефинирајте дополнителни можни фактори со кои можете да ја обезбедите вашата автентикација со лозинка." + }, + "CREATE": { + "TITLE": "Нов фактор", + "DESCRIPTION": "Изберете нов тип на фактор." + }, + "DELETE": { + "TITLE": "Избриши фактор", + "DESCRIPTION": "Дали сте сигурни дека сакате да го избришете факторот од подесувањата за најава?" + }, + "TOAST": { + "ADDED": "Успешно додадено.", + "SAVED": "Успешно зачувано.", + "DELETED": "Успешно отстрането." + }, + "TYPE": "Тип", + "MULTIFACTORTYPES": { + "0": "Непознато", + "1": "Отпечаток на прст, безбедносни клучеви, Face ID и другo" + }, + "SECONDFACTORTYPES": { + "0": "Непознато", + "1": "Еднократна лозинка (OTP)", + "2": "Отисок на прст, безбедносни клучеви, Face ID и другo" + } + }, + "LOGINPOLICY": { + "CREATE": { + "TITLE": "Подесување за најава", + "DESCRIPTION": "Дефинирајте како вашите корисници можат да бидат автентицирани во вашата организација." + }, + "IDPS": "Провајдери на идентитет", + "ADDIDP": { + "TITLE": "Додади IDP", + "DESCRIPTION": "Можете да изберете предефинирани или самокреирани IDPs.", + "SELECTIDPS": "Провајдери на идентитет" + }, + "PASSWORDLESS": "Најавување без лозинка", + "PASSWORDLESSTYPE": { + "0": "Не е дозволено", + "1": "Дозволено" + } + }, + "APP": { + "LIST": "Апликации", + "COMPLIANCE": "OIDC Соодветност", + "URLS": "URLs", + "CONFIGURATION": "Конфигурација", + "TOKEN": "Подесувања за токени", + "PAGES": { + "TITLE": "Апликација", + "ID": "ID", + "DESCRIPTION": "Овде можете да уредите податоците за вашата апликација и нејзината конфигурација.", + "CREATE": "Креирај апликација", + "CREATE_SELECT_PROJECT": "Прво изберете го вашиот проект", + "CREATE_NEW_PROJECT": "или креирајте нов тука.", + "CREATE_DESC_TITLE": "Внесете ги деталите за вашата апликација чекор по чекор", + "CREATE_DESC_SUB": "Автоматски ќе биде генерирана препорачана конфигурација.", + "STATE": "Статус", + "DATECREATED": "Создадено", + "DATECHANGED": "Изменето", + "URLS": "URLs", + "DELETE": "Избриши апликација", + "DETAIL": { + "TITLE": "Детали", + "STATE": { + "0": "Недефинирано", + "1": "Активно", + "2": "Неактивно" + } + }, + "DIALOG": { + "CONFIG": { + "TITLE": "Промени OIDC конфигурација" + }, + "DELETE": { + "TITLE": "Избриши апликација", + "DESCRIPTION": "Дали сте сигурни дека сакате да ја избришете оваа апликација?" + } + }, + "NEXTSTEPS": { + "TITLE": "Следни Чекори", + "0": { + "TITLE": "Додади улоги", + "DESC": "Внесете ги улогите за вашиот проект" + }, + "1": { + "TITLE": "Додади корисници", + "DESC": "Додади нови корисници од вашата организација" + }, + "2": { + "TITLE": "Помош и Поддршка", + "DESC": "Прочитајте ја нашата документација за креирање на апликации или контактирајте ја нашата поддршка" + } + } + }, + "NAMEDIALOG": { + "TITLE": "Преименувај апликација", + "DESCRIPTION": "Внесете го новото име на вашата апликација", + "NAME": "Ново име" + }, + "NAME": "Име", + "TYPE": "Тип на апликација", + "AUTHMETHOD": "Метод на автентикација", + "AUTHMETHODSECTION": "Метод на автентикација", + "GRANT": "Типови на овластувања", + "ADDITIONALORIGINS": "Дополнителни Origins", + "ADDITIONALORIGINSDESC": "Ако сакате да додадете дополнителни Origins на вашата апликација кои не се користат како Redirect, можете да го направите тоа тука.", + "ORIGINS": "Origins", + "NOTANORIGIN": "Внесената вредност е невалиден Origin", + "PROSWITCH": "Јас сум професионалец. Прескокни го овој водич.", + "NAMEANDTYPESECTION": "Име и Тип", + "TITLEFIRST": "Име на апликацијата", + "TYPETITLE": "Тип на апликација", + "OIDC": { + "WELLKNOWN": "Дополнителни линкови може да се добијат од Discovery endpoint.", + "INFO": { + "ISSUER": "Issuer", + "CLIENTID": "Client Id" + }, + "CURRENT": "Тековна конфигурација", + "TOKENSECTIONTITLE": "Опции за автентикациски токени", + "REDIRECTSECTIONTITLE": "Подесување за пренасочување", + "REDIRECTTITLE": "Наведете URIs каде што ќе се пренасочи најавата.", + "POSTREDIRECTTITLE": "Ова е URI за пренасочување по одјавата.", + "REDIRECTDESCRIPTIONWEB": "URIs за пренасочување мора да започнуваат со https://. http:// е валидно само со овозможен development mode.", + "REDIRECTDESCRIPTIONNATIVE": "URIs за пренасочување мора да започнуваат со вашиот протокол, http://127.0.0.1, http://[::1] или http://localhost.", + "REDIRECTNOTVALID": "Ова URI за пренасочување не е валидно.", + "COMMAORENTERSEPERATION": "одделувајте со ↵", + "TYPEREQUIRED": "Типот е задолжителен.", + "TITLE": "OIDC Конфигурација", + "CLIENTID": "Client Id", + "CLIENTSECRET": "Клиентска тајна", + "CLIENTSECRET_NOSECRET": "Со избраната метода за автентикација, не е потребна тајна и поради тоа не е достапна.", + "CLIENTSECRET_DESCRIPTION": "Чувајте ја вашата клиентска тајна на безбедно место, бидејќи ќе исчезне откако ќе се затвори дијалогот.", + "REGENERATESECRET": "Генерирај нова клиентска тајна", + "DEVMODE": "Development mode", + "DEVMODEDESC": "Внимавајте: Со овозможен Development mode, URIs за пренасочување нема да бидат валидирани.", + "SKIPNATIVEAPPSUCCESSPAGE": "Прескокни страница за успешна најава", + "SKIPNATIVEAPPSUCCESSPAGE_DESCRIPTION": "Прескокнете ја страницата за успешна најава за оваа нативна апликација.", + "REDIRECT": "Redirect URIs", + "REDIRECTSECTION": "Redirect URIs", + "POSTLOGOUTREDIRECT": "URIs по одјавувањето", + "RESPONSESECTION": "Типови на одговори", + "GRANTSECTION": "Типови на овластувања", + "GRANTTITLE": "Изберете ги вашите типови на овластувања. Забелешка: Implicit е достапен само за апликации базирани на веб-прелистувачи.", + "APPTYPE": { + "0": "Веб", + "1": "Кориснички Агент", + "2": "Нативна" + }, + "RESPONSETYPE": "Типови на Одговори", + "RESPONSE": { + "0": "Код", + "1": "ID Токен", + "2": "Токен-ID Токен" + }, + "REFRESHTOKEN": "Токен за Освежување", + "GRANTTYPE": "Типови на Овластувања", + "GRANT": { + "0": "Код на Овластување", + "1": "Implicit", + "2": "Токен за Освежување", + "3": "Код од Уред" + }, + "AUTHMETHOD": { + "0": "Basic", + "1": "Post", + "2": "None", + "3": "Private Key JWT" + }, + "TOKENTYPE": "Тип на Auth Token", + "TOKENTYPE0": "Bearer Token", + "TOKENTYPE1": "JWT", + "UNSECUREREDIRECT": "Сигурноста на Пренасочувањето не е обезбедена. Ве молиме имајте предвид што правите.", + "OVERVIEWSECTION": "Преглед", + "OVERVIEWTITLE": "Сега е комплетирано. Прегледајте ја вашата конфигурација.", + "ACCESSTOKENROLEASSERTION": "Додадете улоги на корисникот во токенот за пристап", + "ACCESSTOKENROLEASSERTION_DESCRIPTION": "Ако е избрано, се додаваат бараните улоги на автентицираниот корисник во токенот за пристап.", + "IDTOKENROLEASSERTION": "Улоги на корисникот внатре во ID токенот", + "IDTOKENROLEASSERTION_DESCRIPTION": "Ако е избрано, се додаваат бараните улоги на автентицираниот корисник во ID токенот.", + "IDTOKENUSERINFOASSERTION": "Информации за корисникот внатре во ID токенот", + "IDTOKENUSERINFOASSERTION_DESCRIPTION": "Овозможува клиентите да добијат информации за профилот, е-поштата, телефонскиот број и адресите од ID токенот.", + "CLOCKSKEW": "Овозможува клиентите да се справуваат со временски неподесеностите меѓу OP и клиентот. Времетраењето (0-5 сек.) ќе биде додадено на exp claim и одземено од iats, auth_time и nbf.", + "RECOMMENDED": "препорачано", + "NOTRECOMMENDED": "не препорачано", + "SELECTION": { + "APPTYPE": { + "WEB": { + "TITLE": "Веб", + "DESCRIPTION": "Редовни веб апликации како .net, PHP, Node.js, Java итн." + }, + "NATIVE": { + "TITLE": "Нативно", + "DESCRIPTION": "Мобилни апликации, десктоп, паметни уреди итн." + }, + "USERAGENT": { + "TITLE": "Кориснички Агент", + "DESCRIPTION": "Single Page Applications (SPA) и воопшто сите JS frameworks кои се извршуваат во прелистувачите" + } + } + } + }, + "API": { + "INFO": { + "CLIENTID": "Client Id" + }, + "REGENERATESECRET": "Регенерирај клиентска тајна", + "SELECTION": { + "TITLE": "API", + "DESCRIPTION": "APIs воопшто" + }, + "AUTHMETHOD": { + "0": "Basic", + "1": "Private Key JWT" + } + }, + "SAML": { + "SELECTION": { + "TITLE": "SAML", + "DESCRIPTION": "SAML Апликации" + }, + "CONFIGSECTION": "SAML Конфигурација", + "URL": "URL каде што се наоѓа Metadata датотеката", + "OR": "или", + "XML": "Подигни Metadata XML", + "METADATA": "Metadata", + "METADATAFROMFILE": "Metadata од датотека" + }, + "AUTHMETHODS": { + "CODE": { + "TITLE": "Code", + "DESCRIPTION": "Замени го авторизацискиот код за токени" + }, + "PKCE": { + "TITLE": "PKCE", + "DESCRIPTION": "Користи random hash наместо статичка клиентска тајна за поголема безбедност" + }, + "POST": { + "TITLE": "POST", + "DESCRIPTION": "Испрати client_id и client_secret како дел од формата" + }, + "PK_JWT": { + "TITLE": "Private Key JWT", + "DESCRIPTION": "Користи приватен клуч за авторизација на твојата апликација" + }, + "BASIC": { + "TITLE": "Basic", + "DESCRIPTION": "Автентикација со Корисничко име и Лозинка" + }, + "IMPLICIT": { + "TITLE": "Implicit", + "DESCRIPTION": "Добиј токени директно од авторизациската точка" + }, + "DEVICECODE": { + "TITLE": "Device Code", + "DESCRIPTION": "Авторизирај го уредот на компјутер или смартфон." + }, + "CUSTOM": { + "TITLE": "Custom", + "DESCRIPTION": "Твојата поставка не одговара на ниту една друга опција." + } + }, + "TOAST": { + "REACTIVATED": "Апликацијата е реактивирана.", + "DEACTIVATED": "Апликацијата е деактивирана.", + "OIDCUPDATED": "Апликацијата е ажурирана.", + "APIUPDATED": "Апликацијата е ажурирана", + "UPDATED": "Апликацијата е ажурирана.", + "CREATED": "Апликацијата е креирана.", + "CLIENTSECRETREGENERATED": "Клиентската тајна е генерирана.", + "DELETED": "Апликацијата е избришана.", + "CONFIGCHANGED": "Детектирани промени!" + } + }, + "GENDERS": { + "0": "Непознато", + "1": "Женски", + "2": "Машки", + "3": "Друго" + }, + "LANGUAGES": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "pl": "Polski", + "zh": "简体中文", + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" + }, + "MEMBER": { + "ADD": "Додај Менаџер", + "CREATIONTYPE": "Тип на креирање", + "CREATIONTYPES": { + "3": "IAM", + "2": "Организација", + "0": "Сопствен Проект", + "1": "Доделен Проект", + "4": "Проект" + }, + "EDITROLE": "Уреди улоги", + "EDITFOR": "Уреди улоги за корисникот: {{value}}", + "DIALOG": { + "DELETE_TITLE": "Отстрани Менаџер", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го отстраните менаџерот?" + } + }, + "ROLESLABEL": "Улоги", + "GRANTS": { + "TITLE": "Овластувања", + "DESC": "Овие се сите овластувања на вашата организација.", + "DELETE": "Избриши Овластување", + "EMPTY": "Не се пронајдени овластувања", + "ADD": "Креирај Овластување", + "ADD_BTN": "Ново", + "PROJECT": { + "TITLE": "Овластување", + "DESCRIPTION": "Дефинирајте овластувања за одредениот проект. Забелешка: Можете да гледате само записи за проекти и корисници за кои имате овластувања." + }, + "USER": { + "TITLE": "Овластување", + "DESCRIPTION": "Дефинирајте овластувања за одредениот корисник. Забелешка: Можете да гледате само записи за проекти и корисници за кои имате овластувања." + }, + "CREATE": { + "TITLE": "Креирај овластување", + "DESCRIPTION": "Пребарајте ја организацијата, проектот и соодветните улоги." + }, + "EDIT": { + "TITLE": "Промени овластување" + }, + "DETAIL": { + "TITLE": "Детали за овластувањето", + "DESCRIPTION": "Тука можете да ги видите сите детали за овластувањето." + }, + "TOAST": { + "UPDATED": "Овластувањето е ажурирано.", + "REMOVED": "Овластувањето е отстрането", + "BULKREMOVED": "Овластувањата се отстранети." + }, + "DIALOG": { + "DELETE_TITLE": "Избриши овластување", + "DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да го избришете ова овластување?", + "BULK_DELETE_TITLE": "Избриши овластувања", + "BULK_DELETE_DESCRIPTION": "Дали сте сигурни дека сакате да ги избришете овие овластувања?" + } + }, + "CHANGES": { + "LISTTITLE": "Последни Промени", + "BOTTOM": "Стигнавте до крајот на листата.", + "LOADMORE": "Вчитај повеќе", + "ORG": { + "TITLE": "Активност", + "DESCRIPTION": "Овде можете да ги видите најновите настани кои предизвикале промена во организацијата." + }, + "PROJECT": { + "TITLE": "Активност", + "DESCRIPTION": "Овде можете да ги видите најновите настани кои предизвикале промена во проектот." + }, + "USER": { + "TITLE": "Активност", + "DESCRIPTION": "Овде можете да ги видите најновите настани кои предизвикале промена во корисникот." + } + } +} diff --git a/console/src/assets/i18n/pl.json b/console/src/assets/i18n/pl.json index fa4603514..33d4fa741 100644 --- a/console/src/assets/i18n/pl.json +++ b/console/src/assets/i18n/pl.json @@ -1040,7 +1040,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "Ustawienia SMTP", @@ -1240,7 +1242,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "Weryfikacja adresu e-mail zakończona", @@ -1339,6 +1343,8 @@ "ALLOWREGISTER_DESC": "Jeśli ta opcja jest zaznaczona, pojawi się dodatkowy krok rejestracji użytkownika w procesie logowania.", "FORCEMFA": "Wymuś MFA", "FORCEMFA_DESC": "Jeśli ta opcja jest zaznaczona, użytkownicy muszą skonfigurować drugi czynnik logowania.", + "FORCEMFALOCALONLY": "Wymuś MFA dla lokalnych użytkowników", + "FORCEMFALOCALONLY_DESC": "Jeśli ta opcja jest zaznaczona, lokalni uwierzytelnieni użytkownicy muszą skonfigurować drugi czynnik logowania.", "HIDEPASSWORDRESET": "Ukryj reset hasła", "HIDEPASSWORDRESET_DESC": "Jeśli ta opcja jest zaznaczona, użytkownik nie może zresetować swojego hasła w procesie logowania.", "HIDELOGINNAMESUFFIX": "Ukryj sufiks nazwy użytkownika", @@ -1506,13 +1512,11 @@ "SEL_PROJECT": "Wyszukaj projekt", "SEL_ROLES": "Wybierz role, które mają zostać dodane do udzielenia ", "SEL_USER": "Wybierz użytkowników", - "SEL_ORG": "Ustaw domenę", - "SEL_ORG_DESC": "Wprowadź pełną domenę, aby określić organizację, której chcesz udzielić dostępu.", - "ORG_TITLE": "Organizacja", + "SEL_ORG": "Wyszukaj organizację", + "SEL_ORG_DESC": "Wyszukaj organizację, której chcesz przyznać.", "ORG_DESCRIPTION": "Masz zamiar udzielić użytkownikowi dostęp dla organizacji {{name}}.", "ORG_DESCRIPTION_DESC": "Przełącz kontekst w nagłówku powyżej, aby udzielić użytkownikowi dostępu dla innej organizacji.", - "SEL_ORG_FORMFIELD": "Pełna domena", - "SEL_ORG_BUTTON": "Wyszukaj organizację", + "SEL_ORG_FORMFIELD": "Organizacja", "FOR_ORG": "Dostęp udzielany:" }, "DETAIL": { @@ -1788,6 +1792,8 @@ "DELETE": "Usuń", "DELETE_TITLE": "Usuń dostawcę tożsamości", "DELETE_DESCRIPTION": "Zamierzasz usunąć dostawcę tożsamości. Spowoduje to nieodwracalne zmiany. Czy na pewno chcesz to zrobić?", + "REMOVE_WARN_TITLE": "Usuń dostawcę tożsamości", + "REMOVE_WARN_DESCRIPTION": "Zamierzasz usunąć dostawcę tożsamości. Spowoduje to usunięcie wyboru dostępnego dostawcy tożsamości dla Twoich użytkowników, a już zarejestrowani użytkownicy nie będą mogli zalogować się ponownie. Czy na pewno chcesz kontynuować?", "DELETE_SELECTION_TITLE": "Usuń dostawcę tożsamości", "DELETE_SELECTION_DESCRIPTION": "Zamierzasz usunąć dostawcę tożsamości. Spowoduje to nieodwracalne zmiany. Czy na pewno chcesz to zrobić?", "EMPTY": "Brak dostawcy tożsamości dostępnego", @@ -2110,7 +2116,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "Dodaj managera", diff --git a/console/src/assets/i18n/pt.json b/console/src/assets/i18n/pt.json new file mode 100644 index 000000000..261061422 --- /dev/null +++ b/console/src/assets/i18n/pt.json @@ -0,0 +1,2190 @@ +{ + "APP_NAME": "ZITADEL", + "PAGINATOR": { + "PREVIOUS": "Anterior", + "NEXT": "Próximo", + "COUNT": "Total de Resultados", + "MORE": "Mais" + }, + "FOOTER": { + "LINKS": { + "CONTACT": "Contato", + "TOS": "Termos de Serviço", + "PP": "Política de Privacidade" + }, + "THEME": { + "DARK": "Escuro", + "LIGHT": "Claro" + } + }, + "HOME": { + "WELCOME": "Comece com ZITADEL", + "DISCLAIMER": "A ZITADEL trata seus dados confidencialmente e com segurança.", + "DISCLAIMERLINK": "Mais informações", + "DOCUMENTATION": { + "TITLE": "Documentação", + "DESCRIPTION": "Comece rapidamente com ZITADEL." + }, + "GETSTARTED": { + "TITLE": "Comece com ZITADEL", + "DESCRIPTION": "Comece rapidamente com ZITADEL." + }, + "QUICKSTARTS": { + "LABEL": "Primeiros Passos", + "TITLE": "Início Rápido", + "DESCRIPTION": "Comece rapidamente com ZITADEL." + }, + "SHORTCUTS": { + "SHORTCUTS": "Atalhos", + "SETTINGS": "Atalhos disponíveis", + "PROJECTS": "Projetos", + "REORDER": "Mantenha e arraste o bloco para movê-lo", + "ADD": "Mantenha e arraste um bloco para adicionar" + } + }, + "ONBOARDING": { + "DESCRIPTION": "Seu processo de integração", + "MOREDESCRIPTION": "mais atalhos", + "COMPLETED": "concluído", + "DISMISS": "Não, obrigado, sou um profissional.", + "CARD": { + "TITLE": "Inicie o ZITADEL", + "DESCRIPTION": "Esta lista de verificação ajuda a configurar sua instância e orienta você nas etapas mais essenciais" + }, + "EVENTS": { + "instance.policy.label.added": { + "title": "Configure sua marca", + "description": "Defina cores e forma para o seu login e faça o upload do seu logotipo e ícones.", + "action": "Configurar marca" + }, + "instance.smtp.config.added": { + "title": "Configure as configurações SMTP", + "description": "Configure as configurações do seu próprio servidor de e-mail.", + "action": "Configurar SMTP" + }, + "project.added": { + "title": "Crie um projeto", + "description": "Adicione um projeto e defina suas funções e autorizações.", + "action": "Criar projeto" + }, + "project.application.added": { + "title": "Crie um aplicativo", + "description": "Crie um aplicativo da web, nativo, API ou SAML e configure o fluxo de autenticação.", + "action": "Criar aplicativo" + }, + "user.human.added": { + "title": "Adicione usuários", + "description": "Adicione usuários do seu aplicativo", + "action": "Adicionar usuário" + }, + "user.grant.added": { + "title": "Conceda permissões aos usuários", + "description": "Permita que os usuários acessem seu aplicativo e configure suas funções.", + "action": "Conceder permissões" + } + } + }, + "MENU": { + "INSTANCE": "Instância", + "DASHBOARD": "Início", + "PERSONAL_INFO": "Informações Pessoais", + "DOCUMENTATION": "Documentação", + "INSTANCEOVERVIEW": "Instância", + "ORGS": "Organizações", + "VIEWS": "Visualizações", + "EVENTS": "Eventos", + "FAILEDEVENTS": "Eventos com Falha", + "ORGANIZATION": "Organização", + "DOMAINS": "Domínios", + "PROJECT": "Projetos", + "PROJECTOVERVIEW": "Visão Geral", + "PROJECTGRANTS": "Autorizações", + "ROLES": "Funções", + "GRANTEDPROJECT": "Projetos Concedidos", + "HUMANUSERS": "Usuários", + "MACHINEUSERS": "Usuários de Serviço", + "LOGOUT": "Encerrar Sessão de Todos os Usuários", + "NEWORG": "Nova Organização", + "IAMADMIN": "Você é um Administrador IAM. Observe que você possui permissões estendidas.", + "SHOWORGS": "Mostrar Todas as Organizações", + "GRANTS": "Autorizações", + "ACTIONS": "Ações", + "PRIVACY": "Privacidade", + "TOS": "Termos de Serviço", + "OPENSHORTCUTSTOOLTIP": "Digite ? para mostrar os atalhos do teclado", + "SETTINGS": "Configurações", + "CUSTOMERPORTAL": "Portal do Cliente" + }, + "ACTIONS": { + "ACTIONS": "Ações", + "FILTER": "Filtrar", + "RENAME": "Renomear", + "SET": "Definir", + "COPY": "Copiar para a Área de Transferência", + "COPIED": "Copiado para a área de transferência.", + "RESET": "Redefinir", + "RESETDEFAULT": "Redefinir para o Padrão", + "RESETTO": "Redefinir para: ", + "RESETCURRENT": "Redefinir para o atual", + "SHOW": "Mostrar", + "HIDE": "Ocultar", + "SAVE": "Salvar", + "SAVENOW": "Salvar agora", + "NEW": "Novo", + "ADD": "Adicionar", + "CREATE": "Criar", + "CONTINUE": "Continuar", + "BACK": "Voltar", + "CLOSE": "Fechar", + "CLEAR": "Limpar", + "CANCEL": "Cancelar", + "INFO": "Informações", + "OK": "OK", + "SELECT": "Selecionar", + "VIEW": "Mostrar", + "SELECTIONDELETE": "Excluir seleção", + "DELETE": "Excluir", + "REMOVE": "Remover", + "VERIFY": "Verificar", + "FINISH": "Concluir", + "FINISHED": "Fechar", + "CHANGE": "Alterar", + "REACTIVATE": "Reativar", + "ACTIVATE": "Ativar", + "DEACTIVATE": "Desativar", + "REFRESH": "Atualizar", + "LOGIN": "Entrar", + "EDIT": "Editar", + "PIN": "Fixar / Desafixar", + "CONFIGURE": "Configurar", + "SEND": "Enviar", + "NEWVALUE": "Novo Valor", + "RESTORE": "Restaurar", + "CONTINUEWITHOUTSAVE": "Continuar sem salvar", + "OF": "de", + "PREVIOUS": "Anterior", + "NEXT": "Próximo", + "MORE": "mais", + "STEP": "Passo", + "SETUP": "Configuração", + "UNSAVEDCHANGES": "Alterações não salvas", + "UNSAVED": { + "DIALOG": { + "DESCRIPTION": "Tem certeza de que deseja descartar esta nova ação? Sua ação será perdida", + "CANCEL": "Cancelar", + "DISCARD": "Descartar" + } + }, + "TABLE": { + "SHOWUSER": "Mostrar usuário {{value}}" + } + }, + "MEMBERROLES": { + "IAM_OWNER": "Tem controle sobre toda a instância, incluindo todas as organizações", + "IAM_OWNER_VIEWER": "Tem permissão para revisar toda a instância, incluindo todas as organizações", + "IAM_ORG_MANAGER": "Tem permissão para criar e gerenciar organizações", + "IAM_USER_MANAGER": "Tem permissão para criar e gerenciar usuários", + "ORG_OWNER": "Tem permissão sobre toda a organização", + "ORG_USER_MANAGER": "Tem permissão para criar e gerenciar usuários da organização", + "ORG_OWNER_VIEWER": "Tem permissão para revisar toda a organização", + "ORG_USER_PERMISSION_EDITOR": "Tem permissão para gerenciar concessões de usuários", + "ORG_PROJECT_PERMISSION_EDITOR": "Tem permissão para gerenciar concessões de projetos", + "ORG_PROJECT_CREATOR": "Tem permissão para criar seus próprios projetos e configurações subjacentes", + "PROJECT_OWNER": "Tem permissão sobre todo o projeto", + "PROJECT_OWNER_VIEWER": "Tem permissão para revisar todo o projeto", + "PROJECT_OWNER_GLOBAL": "Tem permissão sobre todo o projeto", + "PROJECT_OWNER_VIEWER_GLOBAL": "Tem permissão para revisar todo o projeto", + "PROJECT_GRANT_OWNER": "Tem permissão para gerenciar a concessão do projeto", + "PROJECT_GRANT_OWNER_VIEWER": "Tem permissão para revisar a concessão do projeto" + }, + "OVERLAYS": { + "ORGSWITCHER": { + "TEXT": "Todas as configurações e tabelas de organização no console são baseadas em uma organização selecionada. Clique neste botão para trocar de organização ou criar uma nova." + }, + "INSTANCE": { + "TEXT": "Clique aqui para acessar as configurações da instância. Observe que você só tem acesso a este botão se tiver permissões avançadas." + }, + "PROFILE": { + "TEXT": "Aqui você pode alternar entre suas contas de usuário e gerenciar suas sessões e perfil." + }, + "NAV": { + "TEXT": "Esta navegação muda com base na organização selecionada acima ou na sua instância" + }, + "CONTEXTCHANGED": { + "TEXT": "O contexto da organização foi alterado." + }, + "SWITCHEDTOINSTANCE": { + "TEXT": "A visualização mudou para a instância!" + } + }, + "FILTER": { + "TITLE": "Filtro", + "STATE": "Status", + "DISPLAYNAME": "Nome de Exibição do Usuário", + "EMAIL": "E-mail", + "USERNAME": "Nome de Usuário", + "ORGNAME": "Nome da Organização", + "PROJECTNAME": "Nome do Projeto", + "RESOURCEOWNER": "Proprietário do Recurso", + "METHODS": { + "5": "contém", + "7": "termina com", + "1": "igual a" + } + }, + "KEYBOARDSHORTCUTS": { + "TITLE": "Atalhos de Teclado", + "UNDERORGCONTEXT": "Dentro das páginas da organização", + "SIDEWIDE": "Atalhos em todo o site", + "SHORTCUTS": { + "HOME": "Ir para Início", + "INSTANCE": "Ir para Instância", + "ORG": "Ir para Organização", + "ORGSETTINGS": "Ir para Configurações da Organização", + "ORGSWITCHER": "Trocar de Organização", + "ME": "Ir para meu perfil", + "PROJECTS": "Ir para Projetos", + "USERS": "Ir para Usuários", + "USERGRANTS": "Ir para Autorizações", + "ACTIONS": "Ir para Ações e Fluxos", + "DOMAINS": "Ir para Domínios" + } + }, + "RESOURCEID": "ID do Recurso", + "NAME": "Nome", + "VERSION": "Versão", + "TABLE": { + "NOROWS": "Sem dados" + }, + "ERRORS": { + "REQUIRED": "Por favor, preencha este campo.", + "ATLEASTONE": "Forneça pelo menos um valor.", + "TOKENINVALID": { + "TITLE": "Seu token de autorização expirou.", + "DESCRIPTION": "Clique no botão abaixo para fazer login novamente." + }, + "EXHAUSTED": { + "TITLE": "Sua cota para solicitações autenticadas está esgotada.", + "DESCRIPTION": "Remova ou aumente o limite de cota para esta instância ZITADEL." + }, + "INVALID_FORMAT": "O formato é inválido.", + "NOTANEMAIL": "O valor fornecido não é um endereço de e-mail.", + "MINLENGTH": "Deve ter pelo menos {{requiredLength}} caracteres.", + "UPPERCASEMISSING": "Deve incluir uma letra maiúscula.", + "LOWERCASEMISSING": "Deve incluir uma letra minúscula.", + "SYMBOLERROR": "Deve incluir um símbolo ou caractere de pontuação.", + "NUMBERERROR": "Deve incluir um dígito.", + "PWNOTEQUAL": "As senhas fornecidas não correspondem.", + "PHONE": "O número de telefone deve começar com 00 ou +." + }, + "USER": { + "SETTINGS": { + "TITLE": "Configurações", + "GENERAL": "Geral", + "IDP": "Provedores de Identidade", + "SECURITY": "Senha e Segurança", + "KEYS": "Chaves", + "PAT": "Tokens de Acesso Pessoal", + "USERGRANTS": "Autorizações", + "MEMBERSHIPS": "Associações", + "METADATA": "Metadados" + }, + "TITLE": "Informações Pessoais", + "DESCRIPTION": "Gerencie suas informações e configurações de segurança.", + "PAGES": { + "LIST": "Usuários", + "TITLE": "Usuário", + "DESCRIPTION": "Crie novos usuários em sua organização e gerencie os existentes.", + "LISTMACHINE": "Usuários de Serviço", + "DESCRIPTIONMACHINE": "Crie e gerencie Usuários de Serviço de sua organização", + "DETAIL": "Detalhes", + "CREATE": "Criar", + "MY": "Minhas Informações", + "LOGINNAMES": "Nomes de Login", + "LOGINMETHODS": "Métodos de Login", + "LOGINNAMESDESC": "Estes são os seus nomes de login:", + "NOUSER": "Nenhum usuário associado.", + "REACTIVATE": "Reativar", + "DEACTIVATE": "Desativar", + "FILTER": "Filtro", + "STATE": "Status", + "DELETE": "Excluir Usuário", + "UNLOCK": "Desbloquear Usuário", + "GENERATESECRET": "Gerar Segredo do Cliente", + "REMOVESECRET": "Remover Segredo do Cliente", + "LOCKEDDESCRIPTION": "Este usuário foi bloqueado devido a exceder o número máximo de tentativas de login e deve ser desbloqueado para ser usado novamente.", + "DELETEACCOUNT": "Excluir Conta", + "DELETEACCOUNT_DESC": "Se você realizar esta ação, será desconectado e não terá mais acesso à sua conta. Essa ação não pode ser desfeita, portanto, prossiga com cautela.", + "DELETEACCOUNT_BTN": "Excluir Conta", + "DELETEACCOUNT_SUCCESS": "Conta excluída com sucesso!" + }, + "DETAILS": { + "DATECREATED": "Criado", + "DATECHANGED": "Alterado" + }, + "DIALOG": { + "DELETE_TITLE": "Excluir Usuário", + "DELETE_SELF_TITLE": "Excluir Conta", + "DELETE_DESCRIPTION": "Você está prestes a excluir permanentemente um usuário. Tem certeza?", + "DELETE_SELF_DESCRIPTION": "Você está prestes a excluir permanentemente sua conta pessoal. Isso irá desconectá-lo e excluir seu usuário. Essa ação não pode ser desfeita!", + "DELETE_AUTH_DESCRIPTION": "Você está prestes a excluir permanentemente sua conta pessoal. Tem certeza?", + "TYPEUSERNAME": "Digite '{{value}}' para confirmar e excluir o usuário.", + "USERNAME": "Nome de usuário", + "DELETE_BTN": "Excluir permanentemente" + }, + "SENDEMAILDIALOG": { + "TITLE": "Enviar Notificação por E-mail", + "DESCRIPTION": "Clique no botão abaixo para enviar uma notificação para o endereço de e-mail atual ou altere o endereço de e-mail no campo.", + "NEWEMAIL": "Novo endereço de e-mail" + }, + "SECRETDIALOG": { + "CLIENTSECRET": "Segredo do Cliente", + "CLIENTSECRET_DESCRIPTION": "Mantenha seu segredo do cliente em um local seguro, pois ele desaparecerá assim que o diálogo for fechado." + }, + "TABLE": { + "DEACTIVATE": "Desativar", + "ACTIVATE": "Ativar", + "CHANGEDATE": "Última Modificação", + "CREATIONDATE": "Criado Em", + "TYPES": { + "HUMAN": "Usuários", + "MACHINE": "Usuários de Serviço" + }, + "FILTER": { + "0": "Filtrar por Nome de Exibição", + "1": "Filtrar por Nome de Usuário", + "2": "filtrar por Nome de Exibição", + "3": "filtrar por Nome de Usuário", + "4": "filtrar por E-mail", + "5": "filtrar por Nome de Exibição", + "10": "filtrar por nome de organização", + "12": "filtrar por nome de projeto" + }, + "EMPTY": "Nenhum registro" + }, + "PASSWORDLESS": { + "SEND": "Enviar link de registro", + "TABLETYPE": "Tipo", + "TABLESTATE": "Status", + "NAME": "Nome", + "EMPTY": "Nenhum dispositivo configurado", + "TITLE": "Autenticação sem Senha", + "DESCRIPTION": "Adicione Métodos de Autenticação baseados em WebAuthn para fazerlogin no ZITADEL sem senha.", + "MANAGE_DESCRIPTION": "Gerencie os métodos de segundo fator dos seus usuários.", + "U2F": "Adicionar método", + "U2F_DIALOG_TITLE": "Verificar autenticador", + "U2F_DIALOG_DESCRIPTION": "Digite um nome para seu login sem senha usado", + "U2F_SUCCESS": "Autenticação sem senha criada com sucesso!", + "U2F_ERROR": "Ocorreu um erro durante a configuração!", + "U2F_NAME": "Nome do Autenticador", + "TYPE": { + "0": "Nenhum MFA definido", + "1": "One Time Password (OTP)", + "2": "Impressão digital, Chaves de Segurança, Face ID e outros" + }, + "STATE": { + "0": "Nenhum Estado", + "1": "Não Pronto", + "2": "Pronto", + "3": "Excluído" + }, + "DIALOG": { + "DELETE_TITLE": "Remover Método de Autenticação sem Senha", + "DELETE_DESCRIPTION": "Você está prestes a excluir um método de autenticação sem senha. Tem certeza?", + "ADD_TITLE": "Autenticação sem senha", + "ADD_DESCRIPTION": "Selecione uma das opções disponíveis para criar um método de autenticação sem senha.", + "SEND_DESCRIPTION": "Envie a si mesmo um link de registro para o seu endereço de e-mail.", + "SEND": "Enviar link de registro", + "SENT": "O e-mail foi entregue com sucesso. Verifique sua caixa de correio para continuar com a configuração.", + "QRCODE_DESCRIPTION": "Gerar um código QR para escanear com outro dispositivo.", + "QRCODE": "Gerar código QR", + "QRCODE_SCAN": "Escanear este código QR para continuar com a configuração no seu dispositivo.", + "NEW_DESCRIPTION": "Use este dispositivo para configurar a autenticação sem senha.", + "NEW": "Adicionar novo" + } + }, + "MFA": { + "TABLETYPE": "Tipo", + "TABLESTATE": "Status", + "NAME": "Nome", + "EMPTY": "Nenhum fator adicional", + "TITLE": "Autenticação Multifator", + "DESCRIPTION": "Adicione um segundo fator para garantir a segurança ideal da sua conta.", + "MANAGE_DESCRIPTION": "Gerencie os métodos de segundo fator dos seus usuários.", + "ADD": "Adicionar Fator", + "OTP": "Aplicativo de Autenticação para OTP (One-Time Password)", + "OTP_DIALOG_TITLE": "Adicionar OTP", + "OTP_DIALOG_DESCRIPTION": "Digitalize o código QR com um aplicativo autenticador e insira o código abaixo para verificar e ativar o método OTP.", + "U2F": "Impressão digital, Chaves de Segurança, Face ID e outros", + "U2F_DIALOG_TITLE": "Verificar Fator", + "U2F_DIALOG_DESCRIPTION": "Digite um nome para o seu fator de multifator universal usado.", + "U2F_SUCCESS": "Fator adicionado com sucesso!", + "U2F_ERROR": "Ocorreu um erro durante a configuração!", + "U2F_NAME": "Nome do Autenticador", + "TYPE": { + "0": "Nenhum MFA definido", + "1": "One Time Password (OTP)", + "2": "Impressão digital, Chaves de Segurança, Face ID e outros" + }, + "STATE": { + "0": "Nenhum Estado", + "1": "Não Pronto", + "2": "Pronto", + "3": "Excluído" + }, + "DIALOG": { + "MFA_DELETE_TITLE": "Remover Segundo Fator", + "MFA_DELETE_DESCRIPTION": "Você está prestes a excluir um segundo fator. Tem certeza?", + "ADD_MFA_TITLE": "Adicionar Segundo Fator", + "ADD_MFA_DESCRIPTION": "Selecione uma das opções disponíveis para criar um método de autenticação de segundo fator." + } + }, + "EXTERNALIDP": { + "TITLE": "Provedores de Identidade Externos", + "DESC": "", + "IDPCONFIGID": "ID da Configuração do Provedor de Identidade", + "IDPNAME": "Nome do Provedor de Identidade", + "USERDISPLAYNAME": "Nome Externo", + "EXTERNALUSERID": "ID do Usuário Externo", + "EMPTY": "Nenhum IDP externo encontrado", + "DIALOG": { + "DELETE_TITLE": "Remover IDP", + "DELETE_DESCRIPTION": "Você está prestes a excluir um Provedor de Identidade de um usuário. Deseja continuar?" + } + }, + "CREATE": { + "TITLE": "Criar um Novo Usuário", + "DESCRIPTION": "Forneça as informações necessárias.", + "NAMEANDEMAILSECTION": "Nome e E-mail", + "GENDERLANGSECTION": "Gênero e Idioma", + "PHONESECTION": "Números de Telefone", + "PASSWORDSECTION": "Senha Inicial", + "ADDRESSANDPHONESECTION": "Número de telefone", + "INITMAILDESCRIPTION": "Se ambas as opções forem selecionadas, nenhum e-mail de inicialização será enviado. Se apenas uma das opções for selecionada, um e-mail para fornecer/verificar os dados será enviado." + }, + "CODEDIALOG": { + "TITLE": "Verificar Número de Telefone", + "DESCRIPTION": "Digite o código que você recebeu por mensagem de texto para verificar seu número de telefone.", + "CODE": "Código" + }, + "DATA": { + "STATE": "Status", + "STATE0": "Desconhecido", + "STATE1": "Ativo", + "STATE2": "Inativo", + "STATE3": "Excluído", + "STATE4": "Bloqueado", + "STATE5": "Suspenso", + "STATE6": "Inicial" + }, + "PROFILE": { + "TITLE": "Perfil", + "EMAIL": "E-mail", + "PHONE": "Número de Telefone", + "PHONE_HINT": "Use 00 ou o símbolo + seguido do código de chamada do país, ou selecione o país na lista suspensa e, em seguida, insira o número de telefone", + "USERNAME": "Nome de Usuário", + "CHANGEUSERNAME": "modificar", + "CHANGEUSERNAME_TITLE": "Alterar nome de usuário", + "CHANGEUSERNAME_DESC": "Digite o novo nome no campo abaixo.", + "FIRSTNAME": "Nome Próprio", + "LASTNAME": "Sobrenome", + "NICKNAME": "Apelido", + "DISPLAYNAME": "Nome de Exibição", + "PREFERRED_LANGUAGE": "Idioma", + "GENDER": "Gênero", + "SENHA": "Senha", + "AVATAR": { + "UPLOADTITLE": "Carregar sua Foto de Perfil", + "UPLOADBTN": "Escolher arquivo", + "UPLOAD": "Carregar", + "CURRENT": "Foto Atual", + "PREVIEW": "Visualização", + "DELETESUCCESS": "Excluído com sucesso!", + "CROPPERERROR": "Ocorreu um erro ao carregar seu arquivo. Tente um formato e tamanho diferentes, se necessário." + }, + "COUNTRY": "País" + }, + "MACHINE": { + "TITLE": "Detalhes do Usuário de Serviço", + "USERNAME": "Nome de Usuário", + "NAME": "Nome", + "DESCRIPTION": "Descrição", + "KEYSTITLE": "Chaves", + "KEYSDESC": "Defina suas chaves e adicione uma data de expiração opcional.", + "TOKENSTITLE": "Tokens de Acesso Pessoal", + "TOKENSDESC": "Os tokens de acesso pessoal funcionam como tokens de acesso OAuth comuns.", + "ID": "ID da Chave", + "TYPE": "Tipo", + "EXPIRATIONDATE": "Data de Expiração", + "CHOOSEDATEAFTER": "Insira uma data de expiração válida após", + "CHOOSEEXPIRY": "Selecione uma data de expiração", + "CREATIONDATE": "Data de Criação", + "KEYDETAILS": "Detalhes da Chave", + "ACCESSTOKENTYPE": "Tipo de Token de Acesso", + "ACCESSTOKENTYPES": { + "0": "Bearer", + "1": "JWT" + }, + "ADD": { + "TITLE": "Adicionar Chave", + "DESCRIPTION": "Selecione o tipo de chave e escolha uma data de expiração opcional." + }, + "ADDED": { + "TITLE": "A chave foi criada", + "DESCRIPTION": "Baixe a chave, pois ela não será mais visível após o fechamento deste diálogo!" + }, + "KEYTYPES": { + "1": "JSON" + }, + "DIALOG": { + "DELETE_KEY": { + "TITLE": "Excluir Chave", + "DESCRIPTION": "Deseja excluir a chave selecionada? Essa ação não pode ser desfeita." + } + } + }, + "PASSWORD": { + "TITLE": "Senha", + "LABEL": "Uma senha segura ajuda a proteger a conta", + "DESCRIPTION": "Digite a nova senha de acordo com a política abaixo.", + "OLD": "Senha Atual", + "NEW": "Nova Senha", + "CONFIRM": "Confirmar Nova Senha", + "NEWINITIAL": "Senha", + "CONFIRMINITIAL": "Confirmar Senha", + "RESET": "Redefinir Senha Atual", + "SET": "Definir Nova Senha", + "RESENDNOTIFICATION": "Enviar Link de Redefinição de Senha", + "REQUIRED": "Algumas informações obrigatórias estão faltando.", + "MINLENGTHERROR": "Deve ter pelo menos {{value}} caracteres." + }, + "ID": "ID", + "EMAIL": "E-mail", + "PHONE": "Número de Telefone", + "PHONEEMPTY": "Nenhum número de telefone definido", + "PHONEVERIFIED": "Número de telefone verificado.", + "EMAILVERIFIED": "E-mail verificado", + "NOTVERIFIED": "não verificado", + "PREFERRED_LOGINNAME": "Nome de Usuário Preferencial", + "ISINITIAL": "O usuário ainda não está ativo.", + "LOGINMETHODS": { + "TITLE": "Informações de Contato", + "DESCRIPTION": "As informações fornecidas serão usadas para enviar informações importantes, como e-mails de redefinição de senha.", + "EMAIL": { + "TITLE": "E-mail", + "VALID": "validado", + "ISVERIFIED": "E-mail Verificado", + "ISVERIFIEDDESC": "Se o e-mail estiver verificado, nenhuma solicitação de verificação será feita.", + "RESEND": "Reenviar E-mail de Verificação", + "EDITTITLE": "Alterar E-mail", + "EDITDESC": "Digite o novo e-mail no campo abaixo." + }, + "PHONE": { + "TITLE": "Telefone", + "VALID": "validado", + "RESEND": "Reenviar Mensagem de Texto de Verificação", + "EDITTITLE": "Alterar Número", + "EDITVALUE": "Número de Telefone", + "EDITDESC": "Digite o novo número de telefone no campo abaixo.", + "DELETETITLE": "Excluir número de telefone", + "DELETEDESC": "Você realmente deseja excluir o número de telefone?" + }, + "RESENDCODE": "Reenviar Código", + "ENTERCODE": "Verificar", + "ENTERCODE_DESC": "Digite o código de verificação" + }, + "GRANTS": { + "TITLE": "Permissões de Usuário", + "DESCRIPTION": "Conceda a este usuário acesso a determinados projetos.", + "CREATE": { + "TITLE": "Criar Permissão de Usuário", + "DESCRIPTION": "Pesquise a organização, o projeto e as funções do projeto correspondentes." + }, + "PROJECTNAME": "Nome do Projeto", + "PROJECT-OWNED": "Projeto", + "PROJECT-GRANTED": "Projeto Concedido", + "FILTER": { + "0": "filtro por usuário", + "1": "filtro por domínio", + "2": "filtro por nome do projeto", + "3": "filtro por nome da função" + } + }, + "STATE": { + "0": "Desconhecido", + "1": "Ativo", + "2": "Inativo", + "3": "Excluído", + "4": "Bloqueado", + "5": "Suspenso", + "6": "Inicial" + }, + "SEARCH": { + "ADDITIONAL": "Nome de usuário (organização atual)", + "ADDITIONAL-EXTERNAL": "Nome de usuário (organização externa)" + }, + "TARGET": { + "SELF": "Se você deseja conceder acesso a um usuário de outra organização", + "EXTERNAL": "Para conceder acesso a um usuário de sua organização", + "CLICKHERE": "clique aqui" + }, + "SIGNEDOUT": "Você saiu. Clique no botão \"Entrar\" para fazer login novamente.", + "SIGNEDOUT_BTN": "Entrar", + "EDITACCOUNT": "Editar Conta", + "ADDACCOUNT": "Entrar Com Outra Conta", + "RESENDINITIALEMAIL": "Reenviar e-mail de ativação", + "RESENDEMAILNOTIFICATION": "Reenviar notificação por e-mail", + "TOAST": { + "CREATED": "Usuário criado com sucesso.", + "SAVED": "Perfil salvo com sucesso.", + "USERNAMECHANGED": "Nome de usuário alterado.", + "EMAILSAVED": "E-mail salvo com sucesso.", + "INITEMAILSENT": "E-mail de ativação enviado.", + "PHONESAVED": "Telefone salvo com sucesso.", + "PHONEREMOVED": "O número de telefone foi removido.", + "PHONEVERIFIED": "Número de telefone verificado com sucesso.", + "PHONEVERIFICATIONSENT": "Código de verificação de telefone enviado.", + "EMAILVERIFICATIONSENT": "Código de verificação de e-mail enviado.", + "OTPREMOVED": "OTP removido.", + "U2FREMOVED": "Fator removido.", + "PASSWORDLESSREMOVED": "Autenticação sem senha removida.", + "INITIALPASSWORDSET": "Senha inicial definida.", + "PASSWORDNOTIFICATIONSENT": "Notificação de alteração de senha enviada.", + "PASSWORDCHANGED": "Senha alterada com sucesso.", + "REACTIVATED": "Usuário reativado.", + "DEACTIVATED": "Usuário desativado.", + "SELECTEDREACTIVATED": "Usuários selecionados reativados.", + "SELECTEDDEACTIVATED": "Usuários selecionados desativados.", + "SELECTEDKEYSDELETED": "Chaves selecionadas excluídas.", + "KEYADDED": "Chave adicionada!", + "MACHINEADDED": "Usuário de serviço criado!", + "DELETED": "Usuário excluído com sucesso!", + "UNLOCKED": "Usuário desbloqueado com sucesso!", + "PASSWORDLESSREGISTRATIONSENT": "Link de registro enviado com sucesso.", + "SECRETGENERATED": "Segredo gerado com sucesso!", + "SECRETREMOVED": "Segredo removido com sucesso!" + }, + "MEMBERSHIPS": { + "TITLE": "Funções de Gerente do ZITADEL", + "DESCRIPTION": "Essas são todas as permissões de membros do usuário. Você também pode modificá-las nas páginas de detalhes da organização, projeto ou IAM.", + "ORGCONTEXT": "Você vê todas as organizações e projetos relacionados à organização atualmente selecionada.", + "USERCONTEXT": "Você vê todas as organizações e projetos para os quais está autorizado. Incluindo outras organizações.", + "CREATIONDATE": "Data de Criação", + "CHANGEDATE": "Última Modificação", + "DISPLAYNAME": "Nome de Exibição", + "REMOVE": "Remover", + "TYPE": "Tipo", + "ORGID": "ID da Organização", + "UPDATED": "A permissão de membro foi atualizada.", + "NOPERMISSIONTOEDIT": "Você não possui as permissões necessárias para editar funções!", + "TYPES": { + "UNKNOWN": "Desconhecido", + "ORG": "Organização", + "PROJECT": "Projeto", + "GRANTEDPROJECT": "Projeto Concedido" + } + }, + "PERSONALACCESSTOKEN": { + "ID": "ID", + "TOKEN": "Token", + "ADD": { + "TITLE": "Gerar Novo Token de Acesso Pessoal", + "DESCRIPTION": "Defina um tempo de expiração personalizado para o token.", + "CHOOSEEXPIRY": "Selecione uma data de expiração", + "CHOOSEDATEAFTER": "Insira uma data de expiração válida após" + }, + "ADDED": { + "TITLE": "Token de Acesso Pessoal", + "DESCRIPTION": "Certifique-se de copiar o seu token de acesso pessoal. Você não poderá vê-lo novamente!" + }, + "DELETE": { + "TITLE": "Excluir Token", + "DESCRIPTION": "Você está prestes a excluir o token de acesso pessoal. Tem certeza?" + }, + "DELETED": "Token excluído com sucesso." + } + }, + "METADATA": { + "TITLE": "Metadados", + "DESCRIPTION": "", + "KEY": "Chave", + "VALUE": "Valor", + "ADD": "Nova Entrada", + "SAVE": "Salvar", + "EMPTY": "Nenhum metadado", + "SETSUCCESS": "Elemento salvo com sucesso", + "REMOVESUCCESS": "Elemento excluído com sucesso" + }, + "FLOWS": { + "TITLE": "Ações e Fluxos", + "DESCRIPTION": "Defina scripts para executar em determinado evento.", + "ACTIONSTITLE": "Ações", + "ACTIONSDESCRIPTION": "Esses são seus scripts que você pode executar nos fluxos.", + "FLOWSTITLE": "Fluxos", + "FLOWSDESCRIPTION": "Fluxos de um determinado tipo executam ações no momento de um gatilho.", + "ID": "ID", + "NAME": "Nome", + "STATE": "Estado", + "STATES": { + "0": "sem status", + "1": "inativo", + "2": "ativo" + }, + "ADDTRIGGER": "Adicionar gatilho", + "FLOWCHANGED": "O fluxo foi alterado com sucesso", + "FLOWCLEARED": "O fluxo foi redefinido com sucesso", + "TIMEOUT": "Tempo Limite", + "TIMEOUTINSEC": "Tempo Limite em segundos", + "ALLOWEDTOFAIL": "Permitido Falhar", + "SCRIPT": "Script", + "FLOWTYPE": "Tipo de Fluxo", + "TRIGGERTYPE": "Tipo de Gatilho", + "ACTIONS": "Ações", + "ACTIONSMAX": "Com base no seu Nível, você tem um número limitado de Ações disponíveis ({{value}}). Certifique-se de desativar as que você não precisa ou considere fazer upgrade do seu nível.", + "DIALOG": { + "ADD": { + "TITLE": "Criar uma Ação" + }, + "UPDATE": { + "TITLE": "Atualizar Ação" + }, + "DELETEACTION": { + "TITLE": "Excluir Ação?", + "DESCRIPTION": "Você está prestes a excluir uma ação. Isso não pode ser desfeito. Tem certeza?", + "DELETE_SUCCESS": "Ação excluída com sucesso." + }, + "CLEAR": { + "TITLE": "Limpar fluxo?", + "DESCRIPTION": "Você está prestes a redefinir o fluxo juntamente com seus gatilhos e ações. Essa alteração não pode ser desfeita. Tem certeza?" + }, + "REMOVEACTIONSLIST": { + "TITLE": "Excluir Ações Selecionadas?", + "DESCRIPTION": "Tem certeza de que deseja excluir as ações selecionadas do fluxo?" + } + }, + "TOAST": { + "ACTIONSSET": "Ações definidas", + "ACTIONREACTIVATED": "Ações reativadas com sucesso", + "ACTIONDEACTIVATED": "Ações desativadas com sucesso" + } + }, + "IAM": { + "TITLE": "Instância", + "DESCRIPTION": "Gerencie as configurações da sua instância e organizações", + "POLICIES": { + "TITLE": "Políticas do sistema e configurações de acesso", + "DESCRIPTION": "Gerencie as políticas globais e configurações de acesso à gerência." + }, + "EVENTSTORE": { + "TITLE": "Administração de armazenamento IAM", + "DESCRIPTION": "Gerencie as visualizações do ZITADEL e eventos falhados." + }, + "MEMBER": { + "TITLE": "Gerentes", + "DESCRIPTION": "Esses gerentes têm permissão para fazer alterações na sua instância." + }, + "PAGES": { + "STATE": "Status", + "DOMAINLIST": "Domínios" + }, + "STATE": { + "0": "Não especificado", + "1": "Criando", + "2": "Executando", + "3": "Parando", + "4": "Parado" + }, + "VIEWS": { + "TITLE": "Visualizações", + "DESCRIPTION": "Este cartão mostra as visualizações do ZITADEL.", + "VIEWNAME": "Nome", + "DATABASE": "Banco de Dados", + "SEQUENCE": "Sequência", + "EVENTTIMESTAMP": "Carimbo de Data/Hora do Evento", + "LASTSPOOL": "Spool bem-sucedido", + "ACTIONS": "Ações", + "CLEAR": "Limpar", + "CLEARED": "Visualização limpa com sucesso!", + "DIALOG": { + "VIEW_CLEAR_TITLE": "Limpar Visualização", + "VIEW_CLEAR_DESCRIPTION": "Você está prestes a limpar uma visualização. A limpeza de uma visualização cria um processo durante o qual os dados possivelmente não estarão disponíveis para os usuários finais. Você tem certeza?" + } + }, + "FAILEDEVENTS": { + "TITLE": "Eventos com falha", + "DESCRIPTION": "Este cartão mostra os eventos com falha.", + "VIEWNAME": "Nome", + "DATABASE": "Banco de Dados", + "FAILEDSEQUENCE": "Sequência com falha", + "FAILURECOUNT": "Contagem de falhas", + "LASTFAILED": "Última falha em", + "ERRORMESSAGE": "Mensagem de erro", + "ACTIONS": "Ações", + "DELETE": "Remover", + "DELETESUCCESS": "Eventos com falha removidos." + }, + "EVENTS": { + "TITLE": "Eventos", + "DESCRIPTION": "Esta visualização mostra todos os eventos ocorridos.", + "EDITOR": "Editor", + "EDITORID": "ID do Editor", + "AGGREGATE": "Agregado", + "AGGREGATEID": "ID do Agregado", + "AGGREGATETYPE": "Tipo do Agregado", + "RESOURCEOWNER": "Proprietário do Recurso", + "SEQUENCE": "Sequência", + "CREATIONDATE": "Criado em", + "TYPE": "Tipo", + "PAYLOAD": "Carga", + "FILTERS": { + "BTN": "Filtrar", + "USER": { + "IDLABEL": "ID", + "CHECKBOX": "Filtrar por Editor" + }, + "AGGREGATE": { + "TYPELABEL": "Tipo de Agregado", + "IDLABEL": "ID", + "CHECKBOX": "Filtrar por Agregado" + }, + "TYPE": { + "TYPELABEL": "Tipo", + "CHECKBOX": "Filtrar por Tipo" + }, + "RESOURCEOWNER": { + "LABEL": "ID", + "CHECKBOX": "Filtrar por Proprietário do Recurso" + }, + "SEQUENCE": { + "LABEL": "Sequência", + "CHECKBOX": "Filtrar por Sequência", + "SORT": "Ordenação", + "ASC": "Crescente", + "DESC": "Decrescente" + }, + "CREATIONDATE": { + "LABEL": "Data de Criação", + "CHECKBOX": "Filtrar por Data de Criação" + }, + "OTHER": "outro", + "OTHERS": "outros" + }, + "DIALOG": { + "TITLE": "Detalhes do Evento" + } + }, + "TOAST": { + "MEMBERREMOVED": "Gerente removido.", + "MEMBERSADDED": "Gerentes adicionados.", + "MEMBERADDED": "Gerente adicionado.", + "MEMBERCHANGED": "Gerente alterado.", + "ROLEREMOVED": "Função removida.", + "ROLECHANGED": "Função alterada.", + "REACTIVATED": "Reativado", + "DEACTIVATED": "Desativado" + } + }, + "ORG": { + "PAGES": { + "NAME": "Nome", + "ID": "ID", + "CREATIONDATE": "Data de Criação", + "DATECHANGED": "Alterado", + "FILTER": "Filtro", + "FILTERPLACEHOLDER": "Filtrar pelo nome", + "LIST": "Organizações", + "LISTDESCRIPTION": "Escolha uma organização.", + "ACTIVE": "Ativa", + "CREATE": "Criar Organização", + "DEACTIVATE": "Desativar Organização", + "REACTIVATE": "Reativar Organização", + "NOPERMISSION": "Você não tem permissão para acessar as configurações da organização.", + "USERSELFACCOUNT": "Use sua conta pessoal como proprietário da organização", + "ORGDETAIL_TITLE": "Digite o nome e domínio da sua nova organização.", + "ORGDETAIL_TITLE_WITHOUT_DOMAIN": "Digite o nome da sua nova organização.", + "ORGDETAILUSER_TITLE": "Configurar Proprietário da Organização", + "DELETE": "Excluir organização", + "DEFAULTLABEL": "Padrão", + "SETASDEFAULT": "Definir como organização padrão", + "DEFAULTORGSET": "Organização padrão alterada com sucesso", + "RENAME": { + "ACTION": "Renomear", + "TITLE": "Renomear Organização", + "DESCRIPTION": "Digite o novo nome para sua organização", + "BTN": "Renomear" + }, + "ORGDOMAIN": { + "TITLE": "Verificação de Propriedade do Domínio da Organização", + "VERIFICATION": "Para verificar a propriedade do seu domínio, você precisa baixar um arquivo de verificação e enviá-lo para a URL fornecida abaixo, ou criar um registro DNS TXT para a URL fornecida. Para concluir, clique no botão para verificar.", + "VERIFICATION_SKIP": "Você pode pular a verificação por enquanto e continuar a criar sua organização, mas para usar sua organização, esta etapa deve ser concluída!", + "VERIFICATION_VALIDATION_DESC": "Os tokens são verificados regularmente para garantir que você ainda seja o proprietário do domínio.", + "VERIFICATION_NEWTOKEN_TITLE": "Solicitar Novo Token", + "VERIFICATION_NEWTOKEN_DESC": "Se você deseja solicitar um novo token, selecione seu método preferido. Se você deseja validar um token persistente, clique no botão acima.", + "VERIFICATION_VALIDATION_ONGOING": "Um token de verificação já foi solicitado. Clique no botão para iniciar uma verificação.", + "VERIFICATION_VALIDATION_ONGOING_TYPE": "Tipo do token:", + "VERIFICATION_SUCCESSFUL": "Domínio verificado com sucesso!", + "REQUESTNEWTOKEN": "Solicitar novo token", + "TYPES": { + "1": "HTTP", + "2": "DNS" + } + }, + "DOWNLOAD_FILE": "Baixar Arquivo", + "SELECTORGTOOLTIP": "Selecionar esta organização.", + "PRIMARYDOMAIN": "Domínio Principal", + "STATE": "Estado", + "USEPASSWORD": "Definir Senha Inicial", + "USEPASSWORDDESC": "O usuário não precisa definir a senha durante a inicialização." + }, + "LIST": { + "TITLE": "Organizações", + "DESCRIPTION": "Estas são as organizações na sua instância" + }, + "DOMAINS": { + "NEW": "Adicionar Domínio", + "TITLE": "Domínios", + "DESCRIPTION": "Configure seus domínios. Este domínio pode ser usado para o login dos seus usuários.", + "SETPRIMARY": "Definir como Principal", + "DELETE": { + "TITLE": "Excluir Domínio", + "DESCRIPTION": "Você está prestes a excluir um dos seus domínios. Observe que seus usuários não poderão mais usar este domínio para fazer login." + }, + "ADD": { + "TITLE": "Adicionar Domínio", + "DESCRIPTION": "Você está prestes a adicionar um domínio para sua organização. Após o processo bem-sucedido, seus usuários poderão usar o domínio para fazer login." + } + }, + "STATE": { + "0": "Não definido", + "1": "Ativa", + "2": "Desativada", + "3": "Removida" + }, + "MEMBER": { + "TITLE": "Gerentes da Organização", + "DESCRIPTION": "Defina os usuários que podem alterar as preferências da sua organização." + }, + "TOAST": { + "UPDATED": "Organização atualizada com sucesso.", + "DEACTIVATED": "Organização desativada.", + "REACTIVATED": "Organização reativada.", + "DOMAINADDED": "Domínio adicionado.", + "DOMAINREMOVED": "Domínio removido.", + "MEMBERADDED": "Gerente adicionado.", + "MEMBERREMOVED": "Gerente removido.", + "MEMBERCHANGED": "Gerente alterado.", + "SETPRIMARY": "Domínio principal definido.", + "DELETED": "Organização excluída com sucesso", + "ORG_WAS_DELETED": "Organização foi excluída." + }, + "DIALOG": { + "DEACTIVATE": { + "TITLE": "Desativar organização", + "DESCRIPTION": "Você está prestes a desativar sua organização. Os usuários não poderão fazer login posteriormente. Tem certeza de que deseja continuar?" + }, + "REACTIVATE": { + "TITLE": "Reativar organização", + "DESCRIPTION": "Você está prestes a reativar sua organização. Os usuários poderão fazer login novamente. Tem certeza de que deseja continuar?" + }, + "DELETE": { + "TITLE": "Excluir organização", + "DESCRIPTION": "Você está prestes a excluir sua organização. Isso inicia um processo no qual todos os dados relacionados à organização serão excluídos. Não será possível reverter esta ação por enquanto.", + "TYPENAME": "Digite '{{value}}' para excluir sua organização.", + "ORGNAME": "Nome", + "BTN": "Excluir" + } + } + }, + "SETTINGS": { + "INSTANCE": { + "TITLE": "Configurações da Instância", + "DESCRIPTION": "Essas configurações serão aplicadas a todas as suas organizações, a menos que tenham sido substituídas." + }, + "ORG": { + "TITLE": "Configurações da Organização", + "DESCRIPTION": "Essas configurações estendem e sobrescrevem as configurações da sua instância." + }, + "LIST": { + "GENERAL": "Geral", + "LOGIN": "Comportamento de Login e Segurança", + "LOCKOUT": "Bloqueio", + "COMPLEXITY": "Complexidade de Senha", + "NOTIFICATIONS": "Configurações de Notificação", + "NOTIFICATIONS_DESC": "Configurações de SMTP e SMS", + "MESSAGETEXTS": "Textos de Mensagem", + "IDP": "Provedores de Identidade", + "DOMAIN": "Configurações de Domínio", + "LOGINTEXTS": "Textos da Interface de Login", + "BRANDING": "Marca", + "PRIVACYPOLICY": "Política de Privacidade", + "OIDC": "Tempo de Vida e Expiração do Token OIDC", + "SECRETS": "Aparência de Segredo", + "SECURITY": "Configurações de Segurança" + }, + "GROUPS": { + "NOTIFICATIONS": "Notificações", + "LOGIN": "Login e Acesso", + "DOMAIN": "Domínio", + "TEXTS": "Textos e Idiomas", + "APPEARANCE": "Aparência", + "OTHER": "Outro" + } + }, + "SETTING": { + "DEFAULTLANGUAGE": "Idioma padrão", + "LANGUAGE": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "pl": "Polski", + "zh": "简体中文", + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" + }, + "SMTP": { + "TITLE": "Configurações SMTP", + "SENDERADDRESS": "Endereço de e-mail do remetente", + "SENDERNAME": "Nome do remetente", + "HOSTANDPORT": "Host e porta", + "USER": "Usuário", + "PASSWORD": "Senha", + "SETPASSWORD": "Definir senha do SMTP", + "PASSWORDSET": "Senha do SMTP definida com sucesso.", + "TLS": "Transport Layer Security (TLS)", + "SAVED": "Salvo com sucesso!", + "REQUIREDWARN": "Para enviar notificações do seu domínio, você precisa inserir seus dados SMTP." + }, + "SMS": { + "TITLE": "Configurações de SMS", + "PROVIDERS": "Provedores", + "PROVIDER": "Provedor de SMS", + "ADDPROVIDER": "Adicionar provedor de SMS", + "ADDPROVIDERDESCRIPTION": "Escolha um dos provedores disponíveis e insira os dados necessários.", + "REMOVEPROVIDER": "Remover provedor", + "REMOVEPROVIDER_DESC": "Você está prestes a excluir uma configuração de provedor. Deseja continuar?", + "SMSPROVIDERSTATE": { + "0": "Não especificado", + "1": "Ativo", + "2": "Inativo" + }, + "ACTIVATED": "Provedor ativado.", + "DEACTIVATED": "Provedor desativado.", + "TWILIO": { + "SID": "SID", + "TOKEN": "Token", + "SENDERNUMBER": "Número do remetente", + "ADDED": "Twilio adicionado com sucesso.", + "REMOVED": "Twilio removido", + "CHANGETOKEN": "Alterar token", + "SETTOKEN": "Definir token", + "TOKENSET": "Token definido com sucesso." + } + }, + "OIDC": { + "TITLE": "Configurações OIDC", + "ACCESSTOKENLIFETIME": "Tempo de vida do token de acesso", + "IDTOKENLIFETIME": "Tempo de vida do token de ID", + "REFRESHTOKENEXPIRATION": "Expiração do token de atualização", + "REFRESHTOKENIDLEEXPIRATION": "Expiração inativa do token de atualização", + "INHOURS": "horas", + "INDAYS": "dias" + }, + "SECRETS": { + "TITLE": "Aparência de segredos", + "TYPES": "Tipos de segredos", + "TYPE": { + "1": "Email de inicialização", + "2": "Verificação de email", + "3": "Verificação de telefone", + "4": "Redefinição de senha", + "5": "Inicialização sem senha", + "6": "Segredo do aplicativo" + }, + "ADDGENERATOR": "Definir aparência de segredo", + "GENERATORTYPE": "Tipo", + "EXPIRY": "Expiração (em horas)", + "INCLUDEDIGITS": "Incluir números", + "INCLUDESYMBOLS": "Incluir símbolos", + "INCLUDELOWERLETTERS": "Incluir letras minúsculas", + "INCLUDEUPPERLETTERS": "Incluir letras maiúsculas", + "LENGTH": "Comprimento", + "UPDATED": "Configurações atualizadas." + }, + "SECURITY": { + "DESCRIPTION": "Essa configuração define o CSP para permitir o enquadramento de um conjunto de domínios permitidos. Observe que, ao permitir o uso de iFrames, você corre o risco de permitir ataques de clickjacking.", + "IFRAMEENABLED": "Permitir iFrame", + "ALLOWEDORIGINS": "URLs permitidos" + }, + "DIALOG": { + "RESET": { + "DEFAULTTITLE": "Redefinir configuração", + "DEFAULTDESCRIPTION": "Você está prestes a redefinir suas configurações para a configuração padrão da sua instância. Tem certeza de que deseja continuar?", + "LOGINPOLICY_DESCRIPTION": "Aviso: Se você continuar, as configurações do provedor de identidade também serão redefinidas para as configurações da instância." + } + } + }, + "POLICY": { + "TITLE": "Explorar configurações", + "DESCRIPTION": "Configurações pré-embaladas que melhoram sua segurança.", + "APPLIEDTO": "Aplicado a", + "PWD_COMPLEXITY": { + "TITLE": "Complexidade da senha", + "DESCRIPTION": "Garante que todas as senhas definidas correspondam a um padrão específico", + "SYMBOLANDNUMBERERROR": "Deve conter um dígito e um símbolo/ponto de pontuação.", + "SYMBOLERROR": "Deve incluir um símbolo/ponto de pontuação.", + "NUMBERERROR": "Deve incluir um dígito.", + "PATTERNERROR": "A senha não atende ao padrão exigido." + }, + "NOTIFICATION": { + "TITLE": "Notificação", + "DESCRIPTION": "Determina em quais alterações as notificações serão enviadas.", + "PASSWORDCHANGE": "Mudança de senha" + }, + "PRIVATELABELING": { + "TITLE": "Marca", + "DESCRIPTION": "Dê ao login o seu estilo personalizado e modifique seu comportamento.", + "PREVIEW_DESCRIPTION": "As alterações da política serão automaticamente aplicadas ao ambiente de visualização.", + "BTN": "Selecionar arquivo", + "ACTIVATEPREVIEW": "Aplicar configuração", + "DARK": "Modo escuro", + "LIGHT": "Modo claro", + "CHANGEVIEW": "Alterar visualização", + "ACTIVATED": "As alterações de política estão agora ATIVAS", + "THEME": "Tema", + "COLORS": "Cores", + "FONT": "Fonte", + "ADVANCEDBEHAVIOR": "Comportamento avançado", + "DROP": "Solte a imagem aqui ou", + "RELEASE": "Liberar", + "DROPFONT": "Solte o arquivo de fonte aqui", + "RELEASEFONT": "Liberar", + "USEOFLOGO": "Seu logotipo será usado no login e nos emails, enquanto o ícone é usado para elementos de IU menores, como o seletor de organização no console", + "MAXSIZE": "O tamanho máximo é limitado a 524kB", + "EMAILNOSVG": "O formato de arquivo SVG não é suportado em emails. Portanto, faça o upload do seu logotipo em PNG ou em outro formato suportado.", + "MAXSIZEEXCEEDED": "Tamanho máximo de 524kB excedido.", + "NOSVGSUPPORTED": "SVG não é suportado!", + "FONTINLOGINONLY": "A fonte está atualmente sendo exibida apenas na interface de login.", + "BACKGROUNDCOLOR": "Cor de fundo", + "PRIMARYCOLOR": "Cor primária", + "WARNCOLOR": "Cor de aviso", + "FONTCOLOR": "Cor da fonte", + "VIEWS": { + "PREVIEW": "Visualização", + "CURRENT": "Configuração atual" + }, + "PREVIEW": { + "TITLE": "Login", + "SECOND": "faça login com sua conta ZITADEL.", + "ERROR": "Usuário não encontrado!", + "PRIMARYBUTTON": "próximo", + "SECONDARYBUTTON": "registrar" + } + }, + "PWD_AGE": { + "TITLE": "Envelhecimento de senha", + "DESCRIPTION": "Você pode definir uma política para o envelhecimento de senhas. Essa política emite um aviso após o tempo de envelhecimento específico ter passado." + }, + "PWD_LOCKOUT": { + "TITLE": "Política de bloqueio", + "DESCRIPTION": "Defina um número máximo de tentativas de senha, após as quais as contas serão bloqueadas." + }, + "DOMAIN_POLICY": { + "TITLE": "Configurações de domínio" + }, + "PRIVATELABELING_POLICY": { + "TITLE": "Marca", + "BTN": "Selecionar arquivo", + "DESCRIPTION": "Personalize a aparência do login", + "ACTIVATEPREVIEW": "Ativar configuração" + }, + "LOGIN_POLICY": { + "TITLE": "Configurações de login", + "DESCRIPTION": "Defina como os usuários podem ser autenticados e configure provedores de identidade", + "DESCRIPTIONCREATEADMIN": "Os usuários podem escolher entre os provedores de identidade disponíveis abaixo.", + "DESCRIPTIONCREATEMGMT": "Os usuários podem escolher entre os provedores de identidade disponíveis abaixo. Observação: você também pode usar provedores definidos pelo sistema e provedores definidos apenas para sua organização.", + "ADVANCED": "Avançado", + "LIFETIMEDURATIONS": "Duração do login", + "SAVED": "Salvo com sucesso!" + }, + "PRIVACY_POLICY": { + "TITLE": "Política de privacidade e TOS", + "DESCRIPTION": "Defina os links para a sua Política de Privacidade e Termos de Serviço", + "TOSLINK": "Link para os Termos de Serviço", + "POLICYLINK": "Link para a Política de Privacidade", + "HELPLINK": "Link para Ajuda", + "SUPPORTEMAIL": "E-mail de suporte", + "SAVED": "Salvo com sucesso!", + "RESET_TITLE": "Restaurar valores padrão", + "RESET_DESCRIPTION": "Você está prestes a restaurar os Links padrão para TOS e Política de Privacidade. Deseja realmente continuar?" + }, + "LOGIN_TEXTS": { + "TITLE": "Textos da interface de login", + "DESCRIPTION": "Defina seus textos para as interfaces de login. Se os textos estiverem vazios, o valor padrão mostrado como marcador de posição será usado.", + "DESCRIPTION_SHORT": "Defina seus textos para as interfaces de login.", + "NEWERVERSIONEXISTS": "Existe uma versão mais recente", + "CURRENTDATE": "Configuração atual", + "CHANGEDATE": "Nova versão a partir de", + "KEYNAME": "Tela/Interface de login", + "RESET_TITLE": "Restaurar valores padrão", + "RESET_DESCRIPTION": "Você está prestes a restaurar todos os valores padrão. Todas as alterações que você fez serão excluídas permanentemente. Deseja realmente continuar?", + "UNSAVED_TITLE": "Continuar sem salvar?", + "UNSAVED_DESCRIPTION": "Você fez alterações sem salvar. Deseja salvar agora?", + "LOCALE": "Código de localidade", + "LOCALES": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "pl": "Polski", + "zh": "简体中文", + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" + }, + "KEYS": { + "emailVerificationDoneText": "Verificação de email concluída", + "emailVerificationText": "Verificação de email", + "externalUserNotFoundText": "Usuário externo não encontrado", + "footerText": "Rodapé", + "initMfaDoneText": "Inicialização de MFA concluída", + "initMfaOtpText": "Inicialização de MFA", + "initMfaPromptText": "Prompt de inicialização de MFA", + "initMfaU2fText": "Inicialização de Fator de Segundo Universal", + "initPasswordDoneText": "Inicialização de senha concluída", + "initPasswordText": "Inicialização de senha", + "initializeDoneText": "Inicialização de usuário concluída", + "initializeUserText": "Inicializaçãode usuário", + "linkingUserDoneText": "Vinculação de usuário concluída", + "loginText": "Login", + "logoutText": "Logout", + "mfaProvidersText": "Provedores de MFA", + "passwordChangeDoneText": "Alteração de senha concluída", + "passwordChangeText": "Alteração de senha", + "passwordResetDoneText": "Redefinição de senha concluída", + "passwordText": "Senha", + "registrationOptionText": "Opções de registro", + "registrationOrgText": "Registrar organização", + "registrationUserText": "Registrar usuário", + "selectAccountText": "Selecionar conta", + "successLoginText": "Login com sucesso", + "usernameChangeDoneText": "Alteração de nome de usuário concluída", + "usernameChangeText": "Alteração de nome de usuário", + "verifyMfaOtpText": "Verificar OTP", + "verifyMfaU2fText": "Verificar Fator de Segundo Universal", + "passwordlessPromptText": "Prompt de autenticação sem senha", + "passwordlessRegistrationDoneText": "Registro sem senha concluído", + "passwordlessRegistrationText": "Registro sem senha", + "passwordlessText": "Sem senha", + "externalRegistrationUserOverviewText": "Visão geral do usuário de registro externo" + } + }, + "MESSAGE_TEXTS": { + "TITLE": "Textos de mensagem", + "DESCRIPTION": "Defina seus textos para os emails de notificação.", + "TYPE": "Notificação", + "TYPES": { + "INIT": "Inicialização", + "VE": "Verificar Email", + "VP": "Verificar Telefone", + "PR": "Redefinição de Senha", + "DC": "Reivindicação de Domínio", + "PL": "Sem senha", + "PC": "Alteração de Senha" + }, + "CHIPS": { + "firstname": "Nome próprio", + "lastname": "Sobrenome", + "code": "Código", + "preferredLoginName": "Nome de login preferido", + "displayName": "Nome de exibição", + "nickName": "Apelido", + "loginnames": "Nomes de login", + "domain": "Domínio", + "lastEmail": "Último email", + "lastPhone": "Último telefone", + "verifiedEmail": "Email verificado", + "verifiedPhone": "Telefone verificado", + "changedate": "Data de alteração", + "username": "Nome de usuário", + "tempUsername": "Nome de usuário temporário" + }, + "TOAST": { + "UPDATED": "Textos personalizados salvos." + } + }, + "DEFAULTLABEL": "As configurações atuais correspondem ao padrão de sua Instância.", + "BTN_INSTALL": "Configurar", + "BTN_EDIT": "Modificar", + "DATA": { + "DESCRIPTION": "Descrição", + "MINLENGTH": "comprimento mínimo", + "HASNUMBER": "tem número", + "HASSYMBOL": "tem símbolo", + "HASLOWERCASE": "tem letra minúscula", + "HASUPPERCASE": "tem letra maiúscula", + "SHOWLOCKOUTFAILURES": "mostrar falhas de bloqueio", + "MAXATTEMPTS": "Máximo de tentativas de senha", + "EXPIREWARNDAYS": "Aviso de expiração após dias", + "MAXAGEDAYS": "Idade máxima em dias", + "USERLOGINMUSTBEDOMAIN": "Adicionar domínio da organização como sufixo aos nomes de login", + "USERLOGINMUSTBEDOMAIN_DESCRIPTION": "Se você habilitar essa configuração, todos os nomes de login serão sufixados com o domínio da organização. Se essa configuração estiver desabilitada, você deve garantir que os nomes de usuário sejam exclusivos em todas as organizações.", + "VALIDATEORGDOMAINS": "Validar domínios da organização", + "SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "O endereço do remetente do SMTP corresponde ao domínio da Instância", + "ALLOWUSERNAMEPASSWORD": "Permitir usuário e senha", + "ALLOWEXTERNALIDP": "Permitir provedor de ID externo", + "ALLOWREGISTER": "Permitir registro", + "ALLOWUSERNAMEPASSWORD_DESC": "O login convencional com nome de usuário e senha é permitido.", + "ALLOWEXTERNALIDP_DESC": "O login é permitido para os provedores de identidade subjacentes", + "ALLOWREGISTER_DESC": "Se a opção estiver selecionada, uma etapa adicional para registrar um usuário aparecerá no login.", + "FORCEMFA": "Forçar MFA", + "FORCEMFA_DESC": "Se a opção estiver selecionada, os usuários deverão configurar um segundo fator para o login.", + "HIDEPASSWORDRESET": "Ocultar redefinição de senha", + "HIDEPASSWORDRESET_DESC": "Se a opção estiver selecionada, o usuário não poderá redefinir sua senha no processo de login.", + "HIDELOGINNAMESUFFIX": "Ocultar sufixo do nome de login", + "HIDELOGINNAMESUFFIX_DESC": "Oculta o sufixo do nome de login na interface de login", + "IGNOREUNKNOWNUSERNAMES": "Ignorar nomes de usuário desconhecidos", + "IGNOREUNKNOWNUSERNAMES_DESC": "Se a opção estiver selecionada, a tela de senha será exibida no processo de login, mesmo se o usuário não for encontrado. O erro na verificação de senha não revelará se o nome de usuário ou a senha estavam incorretos.", + "ALLOWDOMAINDISCOVERY": "Permitir descoberta de domínio", + "ALLOWDOMAINDISCOVERY_DESC": "Se a opção estiver selecionada, o sufixo (@domain.com) de um nome de usuário desconhecido inserido na tela de login será comparado com os domínios da organização e será redirecionado para o registro dessa organização em caso de sucesso.", + "DISABLELOGINWITHEMAIL": "Desativar login com endereço de email", + "DISABLELOGINWITHPHONE": "Desativar login com número de telefone", + "DEFAULTREDIRECTURI": "URI de redirecionamento padrão", + "DEFAULTREDIRECTURI_DESC": "Define para onde o usuário será redirecionado se o login for iniciado sem um contexto de aplicativo (por exemplo, a partir do e-mail)", + "ERRORMSGPOPUP": "Mostrar Erro em Diálogo", + "DISABLEWATERMARK": "Ocultar Marca d'água", + "DISABLEWATERMARK_DESC": "Ocultar a marca d'água Powered by ZITADEL na interface de login", + "PASSWORDCHECKLIFETIME": "Vida Útil da Verificação de Senha", + "EXTERNALLOGINCHECKLIFETIME": "Vida Útil da Verificação de Login Externo", + "MFAINITSKIPLIFETIME": "Vida Útil da Inicialização de Multifator", + "SECONDFACTORCHECKLIFETIME": "Vida Útil da Verificação de Segundo Fator", + "MULTIFACTORCHECKLIFETIME": "Vida Útil da Verificação de Multifator", + "INHOURS": "horas" + }, + "RESET": "Redefinir para o padrão da instância", + "CREATECUSTOM": "Criar Política Personalizada", + "TOAST": { + "SET": "Política definida com sucesso!", + "RESETSUCCESS": "Política redefinida com sucesso!", + "UPLOADSUCCESS": "Enviado com sucesso!", + "DELETESUCCESS": "Excluído com sucesso!", + "UPLOADFAILED": "Falha no envio!" + } + }, + "ORG_DETAIL": { + "TITLE": "Organização", + "DESCRIPTION": "Aqui você pode editar a configuração da sua organização e gerenciar os membros.", + "DETAIL": { + "TITLE": "Detalhes", + "NAME": "Nome", + "DOMAIN": "Domínio", + "STATE": { + "0": "Não definido", + "1": "Ativo", + "2": "Inativo" + } + }, + "MEMBER": { + "TITLE": "Membros", + "USERNAME": "Nome de Usuário", + "DISPLAYNAME": "Nome de Exibição", + "LOGINNAME": "Nome de Login", + "EMAIL": "E-mail", + "ROLES": "Funções", + "ADD": "Adicionar Membro", + "ADDDESCRIPTION": "Insira os nomes dos usuários a serem adicionados." + }, + "TABLE": { + "TOTAL": "Total de Entradas", + "SELECTION": "Elementos Selecionados", + "DEACTIVATE": "Desativar Usuário", + "ACTIVATE": "Ativar Usuário", + "DELETE": "Excluir Usuário", + "CLEAR": "Limpar seleção" + } + }, + "PROJECT": { + "PAGES": { + "TITLE": "Projeto", + "DESCRIPTION": "Aqui você pode definir aplicativos, gerenciar funções e conceder acesso a outras organizações para usar o seu projeto.", + "DELETE": "Excluir Projeto", + "LIST": "Projetos", + "LISTDESCRIPTION": "Se você não consegue encontrar um projeto, entre em contato com o proprietário do projeto ou alguém com os direitos correspondentes para obter acesso ao projeto.", + "DETAIL": "Detalhes", + "CREATE": "Criar Projeto", + "CREATE_DESC": "Insira o nome do seu projeto.", + "ROLE": "Função", + "NOITEMS": "Nenhum projeto", + "ZITADELPROJECT": "Isto pertence ao projeto ZITADEL. Atenção: Se você fizer alterações, o ZITADEL pode não funcionar como o esperado.", + "TYPE": { + "OWNED": "Projetos Próprios", + "GRANTED": "Projetos Concedidos", + "OWNED_SINGULAR": "Projeto Próprio", + "GRANTED_SINGULAR": "Projeto Concedido" + }, + "PRIVATELABEL": { + "TITLE": "Configuração de Marca", + "0": { + "TITLE": "Não Especificado", + "DESC": "Assim que o usuário for identificado, a marca da organização do usuário identificado será exibida antes da marca padrão do sistema." + }, + "1": { + "TITLE": "Usar configuração do projeto", + "DESC": "Será exibida a marca da organização que possui o projeto" + }, + "2": { + "TITLE": "Usar configuração da organização do usuário", + "DESC": "Será exibida a marca da organização do projeto, mas assim que o usuário for identificado, será exibida a configuração da organização do usuário identificado." + }, + "DIALOG": { + "TITLE": "Configuração de Marca", + "DESCRIPTION": "Selecione o comportamento do login ao usar o projeto." + } + }, + "PINNED": "Fixado", + "ALL": "Todos", + "CREATEDON": "Criado em", + "LASTMODIFIED": "Última modificação em", + "ADDNEW": "Criar Novo Projeto", + "DIALOG": { + "REACTIVATE": { + "TITLE": "Reativar Projeto", + "DESCRIPTION": "Tem certeza de que deseja reativar o seu projeto?" + }, + "DEACTIVATE": { + "TITLE": "Desativar Projeto", + "DESCRIPTION": "Tem certeza de que deseja desativar o seu projeto?" + }, + "DELETE": { + "TITLE": "Excluir Projeto", + "DESCRIPTION": "Tem certeza de que deseja excluir o seu projeto?", + "TYPENAME": "Digite o nome do projeto para excluí-lo permanentemente." + } + } + }, + "SETTINGS": { + "TITLE": "Configurações", + "DESCRIPTION": "" + }, + "STATE": { + "TITLE": "Status", + "0": "Não definido", + "1": "Ativo", + "2": "Inativo" + }, + "TYPE": { + "TITLE": "Tipo", + "0": "Tipo desconhecido", + "1": "Próprio", + "2": "Concedido" + }, + "NAME": "Nome", + "NAMEDIALOG": { + "TITLE": "Renomear Projeto", + "DESCRIPTION": "Digite o novo nome para o seu projeto", + "NAME": "Novo Nome" + }, + "MEMBER": { + "TITLE": "Gerentes", + "TITLEDESC": "Os gerentes podem fazer alterações neste projeto com base em sua função.", + "DESCRIPTION": "Esses gerentes podem ter permissão para editar o seu projeto.", + "USERNAME": "Nome de Usuário", + "DISPLAYNAME": "Nome de Exibição", + "LOGINNAME": "Nome de Login", + "EMAIL": "E-mail", + "ROLES": "Funções", + "USERID": "ID do Usuário" + }, + "GRANT": { + "EMPTY": "Nenhuma organização concedida.", + "TITLE": "Concessões de Projeto", + "DESCRIPTION": "Permite que outra organização use o seu projeto.", + "EDITTITLE": "Editar funções", + "CREATE": { + "TITLE": "Criar Concessão de Organização", + "SEL_USERS": "Selecione os usuários aos quais deseja conceder acesso", + "SEL_PROJECT": "Buscar um projeto", + "SEL_ROLES": "Selecione as funções que deseja adicionar à concessão", + "SEL_USER": "Selecione usuários", + "SEL_ORG": "Definir o domínio", + "SEL_ORG_DESC": "Insira o domínio completo para especificar a organização a ser concedida.", + "ORG_TITLE": "Organização", + "ORG_DESCRIPTION": "Você está prestes a conceder um usuário para a organização {{name}}.", + "ORG_DESCRIPTION_DESC": "Altere o contexto no cabeçalho acima para conceder um usuário para outra organização.", + "SEL_ORG_FORMFIELD": "Domínio Completo", + "SEL_ORG_BUTTON": "Buscar Organização", + "FOR_ORG": "A concessão é criada para:" + }, + "DETAIL": { + "TITLE": "Concessão de Projeto", + "DESC": "Você pode selecionar quais funções podem ser usadas pela organização especificada e eleger gerentes", + "MEMBERTITLE": "Gerentes", + "MEMBERDESC": "Estes são os gerentes da organização concedida. Adicione usuários aqui que devem ter acesso para editar os dados do projeto.", + "PROJECTNAME": "Nome do Projeto", + "GRANTEDORG": "Organização Concedida", + "RESOURCEOWNER": "Proprietário do Recurso" + }, + "STATE": "Status", + "STATES": { + "1": "Ativo", + "2": "Inativo" + }, + "ALL": "Todos", + "SHOWDETAIL": "Mostrar Detalhes", + "USER": "Usuário", + "MEMBERS": "Gerentes", + "ORG": "Organização", + "PROJECTNAME": "Nome do Projeto", + "GRANTEDORG": "Organização Concedida", + "GRANTEDORGDOMAIN": "Domínio", + "RESOURCEOWNER": "Proprietário do Recurso", + "GRANTEDORGNAME": "Nome da Organização", + "GRANTID": "ID da Concessão", + "CREATIONDATE": "Data de Criação", + "CHANGEDATE": "Última modificação", + "DATES": "Datas", + "ROLENAMESLIST": "Funções", + "NOROLES": "Nenhuma função", + "TYPE": "Tipo", + "TOAST": { + "PROJECTGRANTUSERGRANTADDED": "Concessão de projeto criada.", + "PROJECTGRANTADDED": "Concessão de projeto criada.", + "PROJECTGRANTCHANGED": "Concessão de projeto alterada.", + "PROJECTGRANTMEMBERADDED": "Gerente da concessão adicionado.", + "PROJECTGRANTMEMBERCHANGED": "Gerente da concessão alterado.", + "PROJECTGRANTMEMBERREMOVED": "Gerente da concessão removido.", + "PROJECTGRANTUPDATED": "Concessão de Projeto atualizada" + }, + "DIALOG": { + "DELETE_TITLE": "Excluir concessão de projeto", + "DELETE_DESCRIPTION": "Você está prestes a excluir uma concessão de projeto. Tem certeza?" + }, + "ROLES": "Funções do Projeto" + }, + "APP": { + "TITLE": "Aplicativos", + "NAME": "Nome", + "NAMEREQUIRED": "É necessário um nome." + }, + "ROLE": { + "EMPTY": "Nenhuma função foi criada ainda.", + "ADDNEWLINE": "Adicionar função adicional", + "KEY": "Chave", + "TITLE": "Funções", + "DESCRIPTION": "Defina algumas funções que podem ser usadas para criar concessões de projeto.", + "NAME": "Nome", + "DISPLAY_NAME": "Nome de Exibição", + "GROUP": "Grupo", + "ACTIONS": "Ações", + "ADDTITLE": "Criar Função", + "ADDDESCRIPTION": "Insira os dados para a nova função.", + "EDITTITLE": "Editar Função", + "EDITDESCRIPTION": "Insira os novos dados para a função.", + "DELETE": "Excluir Função", + "CREATIONDATE": "Criada em", + "CHANGEDATE": "Última modificação", + "SELECTGROUPTOOLTIP": "Selecione todas as funções do grupo {{group}}.", + "OPTIONS": "Opções", + "ASSERTION": "Afirma Funções na Autenticação", + "ASSERTION_DESCRIPTION": "As informações de função são enviadas pelo ponto de extremidade Userinfo e dependendo das configurações do seu aplicativo em tokens e outros tipos.", + "CHECK": "Verificar autorização na Autenticação", + "CHECK_DESCRIPTION": "Se definido, os usuários só podem fazer login se alguma função for atribuída à sua conta.", + "DIALOG": { + "DELETE_TITLE": "Excluir função", + "DELETE_DESCRIPTION": "Você está prestes a excluir uma função de projeto. Tem certeza?" + } + }, + "HAS_PROJECT": "Verificar Projeto na Autenticação", + "HAS_PROJECT_DESCRIPTION": "Verifica se a organização dousuário possui este projeto. Se não possuir, o usuário não poderá ser autenticado.", + "TABLE": { + "TOTAL": "Total de Entradas:", + "SELECTION": "Elementos Selecionados", + "DEACTIVATE": "Desativar Projeto", + "ACTIVATE": "Ativar Projeto", + "DELETE": "Excluir Projeto", + "ORGNAME": "Nome da Organização", + "ORGDOMAIN": "Domínio da Organização", + "STATE": "Status", + "TYPE": "Tipo", + "CREATIONDATE": "Criado em", + "CHANGEDATE": "Última modificação", + "RESOURCEOWNER": "Proprietário do Recurso", + "SHOWTABLE": "Mostrar tabela", + "SHOWGRID": "Mostrar grade", + "EMPTY": "Nenhum projeto encontrado" + }, + "TOAST": { + "MEMBERREMOVED": "Gerente removido.", + "MEMBERSADDED": "Gerentes adicionados.", + "MEMBERADDED": "Gerente adicionado.", + "MEMBERCHANGED": "Gerente alterado.", + "ROLESCREATED": "Funções criadas.", + "ROLEREMOVED": "Função removida.", + "ROLECHANGED": "Função alterada.", + "REACTIVATED": "Reativado.", + "DEACTIVATED": "Desativado.", + "CREATED": "Projeto criado.", + "UPDATED": "Projeto alterado.", + "GRANTUPDATED": "Concessão alterada.", + "DELETED": "Projeto excluído." + } + }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "Excluir função", + "DELETE_DESCRIPTION": "Você está prestes a excluir uma função. Tem certeza?" + } + }, + "NEXTSTEPS": { + "TITLE": "Próximos Passos" + }, + "IDP": { + "LIST": { + "TITLE": "Provedores de Identidade", + "DESCRIPTION": "Gerencie a configuração do seu Provedor de Identidade, que pode ser ativado nas suas Configurações de Login.", + "ACTIVETITLE": "Provedores de Identidade Ativos" + }, + "CREATE": { + "TITLE": "Adicionar provedor", + "DESCRIPTION": "Selecione um ou mais dos seguintes provedores.", + "STEPPERTITLE": "Criar Provedor", + "OIDC": { + "TITLE": "Provedor OIDC", + "DESCRIPTION": "Insira os dados necessários para o seu provedor OIDC." + }, + "OAUTH": { + "TITLE": "Provedor OAuth", + "DESCRIPTION": "Insira os dados necessários para o seu provedor OAuth." + }, + "JWT": { + "TITLE": "Provedor JWT", + "DESCRIPTION": "Insira os dados necessários para o seu provedor JWT." + }, + "GOOGLE": { + "TITLE": "Provedor Google", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade do Google" + }, + "GITLAB": { + "TITLE": "Provedor Gitlab", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade do Gitlab" + }, + "GITLABSELFHOSTED": { + "TITLE": "Provedor Gitlab Self Hosted", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade do Gitlab Self Hosted" + }, + "GITHUBES": { + "TITLE": "Provedor GitHub Enterprise Server", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade do GitHub Enterprise Server" + }, + "GITHUB": { + "TITLE": "Provedor Github", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade do Github" + }, + "AZUREAD": { + "TITLE": "Provedor Microsoft", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade da Microsoft" + }, + "LDAP": { + "TITLE": "Active Directory / LDAP", + "DESCRIPTION": "Insira as credenciais para o seu Provedor de Identidade LDAP" + } + }, + "DETAIL": { + "TITLE": "Provedor de Identidade", + "DESCRIPTION": "Atualize a configuração do seu provedor", + "DATECREATED": "Criado em", + "DATECHANGED": "Última modificação" + }, + "OPTIONS": { + "ISAUTOCREATION": "Criação Automática", + "ISAUTOCREATION_DESC": "Se selecionado, uma conta será criada se ainda não existir.", + "ISAUTOUPDATE": "Atualização Automática", + "ISAUTOUPDATE_DESC": "Se selecionado, as contas são atualizadas ao serem reautenticadas.", + "ISCREATIONALLOWED": "Criação de Conta Permitida", + "ISCREATIONALLOWED_DESC": "Determina se as contas podem ser criadas.", + "ISLINKINGALLOWED": "Vinculação de Conta Permitida", + "ISLINKINGALLOWED_DESC": "Determina se uma identidade pode ser vinculada a uma conta existente." + }, + "OWNERTYPES": { + "0": "desconhecido", + "1": "Instância", + "2": "Organização" + }, + "STATES": { + "1": "ativo", + "2": "inativo" + }, + "AZUREADTENANTTYPES": { + "3": "ID do Locatário", + "0": "Comum", + "1": "Organizações", + "2": "Consumidores" + }, + "AZUREADTENANTTYPE": "Tipo de Locatário", + "AZUREADTENANTID": "ID do Locatário", + "EMAILVERIFIED": "E-mail Verificado", + "NAMEHINT": "Se especificado, será mostrado na interface de login.", + "OPTIONAL": "opcional", + "LDAPATTRIBUTES": "Atributos LDAP", + "UPDATEBINDPASSWORD": "atualizar Senha de Vinculação", + "UPDATECLIENTSECRET": "atualizar segredo do cliente", + "ADD": "Adicionar Provedor de Identidade", + "TYPE": "Tipo", + "OWNER": "Proprietário", + "ID": "ID", + "NAME": "Nome", + "AUTHORIZATIONENDPOINT": "Ponto de Autorização", + "TOKENENDPOINT": "Ponto de Token", + "USERENDPOINT": "Ponto de Usuário", + "IDATTRIBUTE": "Atributo ID", + "AVAILABILITY": "Disponibilidade", + "AVAILABLE": "disponível", + "AVAILABLEBUTINACTIVE": "disponível, mas inativo", + "SETAVAILABLE": "definir como disponível", + "SETUNAVAILABLE": "definir como indisponível", + "CONFIG": "Configuração", + "STATE": "Status", + "ISSUER": "Eu emissor", + "SCOPESLIST": "Lista de Escopos", + "CLIENTID": "ID do Cliente", + "CLIENTSECRET": "Segredo do Cliente", + "LDAPCONNECTION": "Conexão", + "LDAPUSERBINDING": "Vínculo de Usuário", + "BASEDN": "BaseDn", + "BINDDN": "BindDn", + "BINDPASSWORD": "Senha de Vinculação", + "SERVERS": "Servidores", + "STARTTLS": "Iniciar TLS", + "TIMEOUT": "Tempo limite em segundos", + "USERBASE": "Base de Usuários", + "USERFILTERS": "Filtros de Usuário", + "USEROBJECTCLASSES": "Classes de Objeto de Usuário", + "REQUIRED": "obrigatório", + "LDAPIDATTRIBUTE": "atributo ID", + "AVATARURLATTRIBUTE": "atributo URL de Avatar", + "DISPLAYNAMEATTRIBUTE": "atributo de Nome Exibido", + "EMAILATTRIBUTEATTRIBUTE": "atributo de E-mail", + "EMAILVERIFIEDATTRIBUTE": "atributo de E-mail Verificado", + "FIRSTNAMEATTRIBUTE": "atributo de Nome Próprio", + "LASTNAMEATTRIBUTE": "atributo de Sobrenome", + "NICKNAMEATTRIBUTE": "atributo de Apelido", + "PHONEATTRIBUTE": "atributo de Telefone", + "PHONEVERIFIEDATTRIBUTE": "atributo de Telefone Verificado", + "PREFERREDLANGUAGEATTRIBUTE": "atributo de Idioma Preferido", + "PREFERREDUSERNAMEATTRIBUTE": "atributo de Nome de Usuário Preferido", + "PROFILEATTRIBUTE": "atributo de Perfil", + "IDPDISPLAYNAMMAPPING": "Mapeamento de Nome de Exibição do IDP", + "USERNAMEMAPPING": "Mapeamento de Nome de Usuário", + "DATES": "Datas", + "CREATIONDATE": "Criado em", + "CHANGEDATE": "Última Modificação", + "DEACTIVATE": "Desativar", + "ACTIVATE": "Ativar", + "DELETE": "Excluir", + "DELETE_TITLE": "Excluir Provedor de Identidade", + "DELETE_DESCRIPTION": "Você está prestes a excluir um provedor de identidade. As alterações resultantes são irreversíveis. Você realmente deseja fazer isso?", + "DELETE_SELECTION_TITLE": "Excluir Provedor de Identidade", + "DELETE_SELECTION_DESCRIPTION": "Você está prestes a excluir um provedor de identidade. As alterações resultantes são irreversíveis. Você realmente deseja fazer isso?", + "EMPTY": "Nenhum provedor de identidade disponível", + "OIDC": { + "GENERAL": "Informações Gerais", + "TITLE": "Configuração OIDC", + "DESCRIPTION": "Insira os dados para o Provedor de Identidade OIDC." + }, + "JWT": { + "TITLE": "Configuração JWT", + "DESCRIPTION": "Insira os dados para o Provedor de Identidade JWT.", + "HEADERNAME": "Nome do Cabeçalho", + "JWTENDPOINT": "Endpoint JWT", + "JWTKEYSENDPOINT": "Endpoint de Chaves JWT" + }, + "TOAST": { + "SAVED": "Salvo com sucesso.", + "REACTIVATED": "Provedor de identidade reativado.", + "DEACTIVATED": "Provedor de identidade desativado.", + "SELECTEDREACTIVATED": "Provedores de identidade selecionados reativados.", + "SELECTEDDEACTIVATED": "Provedores de identidade selecionados desativados.", + "SELECTEDKEYSDELETED": "Provedores de identidade selecionados excluídos.", + "DELETED": "Provedor de identidade removido com sucesso!", + "ADDED": "Adicionado com sucesso.", + "REMOVED": "Removido com sucesso." + } + }, + "MFA": { + "LIST": { + "MULTIFACTORTITLE": "Sem Senha", + "MULTIFACTORDESCRIPTION": "Defina seus Multifactores para autenticação sem senha aqui.", + "SECONDFACTORTITLE": "Autenticação Multifator", + "SECONDFACTORDESCRIPTION": "Defina outros fatores possíveis com os quais você pode proteger a autenticação por senha." + }, + "CREATE": { + "TITLE": "Novo Fator", + "DESCRIPTION": "Selecione o tipo do novo fator." + }, + "DELETE": { + "TITLE": "Excluir Fator", + "DESCRIPTION": "Você está prestes a excluir um fator das Configurações de Login. Tem certeza?" + }, + "TOAST": { + "ADDED": "Adicionado com sucesso.", + "SAVED": "Salvo com sucesso.", + "DELETED": "Removido com sucesso" + }, + "TYPE": "Tipo", + "MULTIFACTORTYPES": { + "0": "Desconhecido", + "1": "Impressão Digital, Chaves de Segurança, Face ID e outros" + }, + "SECONDFACTORTYPES": { + "0": "Desconhecido", + "1": "Senha de Uso Único (OTP)", + "2": "Impressão Digital, Chaves de Segurança, Face ID e outros" + } + }, + "LOGINPOLICY": { + "CREATE": { + "TITLE": "Configurações de Login", + "DESCRIPTION": "Defina como seus usuários podem ser autenticados na sua organização." + }, + "IDPS": "Provedores de Identidade", + "ADDIDP": { + "TITLE": "Adicionar Provedor de Identidade", + "DESCRIPTION": "Você pode selecionar provedores pré-definidos ou criados por você para autenticação.", + "SELECTIDPS": "Provedores de identidade" + }, + "PASSWORDLESS": "Login sem Senha", + "PASSWORDLESSTYPE": { + "0": "Não permitido", + "1": "Permitido" + } + }, + "APP": { + "LIST": "Aplicações", + "COMPLIANCE": "Conformidade OIDC", + "URLS": "URLs", + "CONFIGURATION": "Configuração", + "TOKEN": "Configurações de Token", + "PAGES": { + "TITLE": "Aplicativo", + "ID": "ID", + "DESCRIPTION": "Aqui você pode editar os dados do seu aplicativo e sua configuração.", + "CREATE": "Criar aplicativo", + "CREATE_SELECT_PROJECT": "Selecione o seu projeto primeiro", + "CREATE_NEW_PROJECT": "ou crie um novo aqui.", + "CREATE_DESC_TITLE": "Insira os Detalhes do seu Aplicativo Passo a Passo", + "CREATE_DESC_SUB": "Uma configuração recomendada será gerada automaticamente.", + "STATE": "Status", + "DATECREATED": "Criado", + "DATECHANGED": "Alterado", + "URLS": "URLs", + "DELETE": "Excluir App", + "DETAIL": { + "TITLE": "Detalhe", + "STATE": { + "0": "Não definido", + "1": "Ativo", + "2": "Inativo" + } + }, + "DIALOG": { + "CONFIG": { + "TITLE": "Alterar Configuração OIDC" + }, + "DELETE": { + "TITLE": "Excluir App", + "DESCRIPTION": "Você realmente deseja excluir este aplicativo?" + } + }, + "NEXTSTEPS": { + "TITLE": "Próximos Passos", + "0": { + "TITLE": "Adicionar funções", + "DESC": "Insira as funções do seu projeto" + }, + "1": { + "TITLE": "Adicionar usuários", + "DESC": "Adicione novos usuários da sua organização" + }, + "2": { + "TITLE": "Ajuda e Suporte", + "DESC": "Leia nossa documentação sobre como criar aplicativos ou entre em contato com nosso suporte" + } + } + }, + "NAMEDIALOG": { + "TITLE": "Renomear Aplicativo", + "DESCRIPTION": "Digite o novo nome para o seu aplicativo", + "NAME": "Novo Nome" + }, + "NAME": "Nome", + "TYPE": "Tipo de Aplicativo", + "AUTHMETHOD": "Método de Autenticação", + "AUTHMETHODSECTION": "Método de Autenticação", + "GRANT": "Tipos de Concessão", + "ADDITIONALORIGINS": "Origens Adicionais", + "ADDITIONALORIGINSDESC": "Se você deseja adicionar origens adicionais ao seu aplicativo que não são usadas como redirecionamento, você pode fazer isso aqui.", + "ORIGINS": "Origens", + "NOTANORIGIN": "O valor inserido não é uma origem", + "PROSWITCH": "Sou um profissional. Pular este assistente.", + "NAMEANDTYPESECTION": "Nome e Tipo", + "TITLEFIRST": "Nome do aplicativo", + "TYPETITLE": "Tipo de aplicativo", + "OIDC": { + "WELLKNOWN": "Links adicionais podem ser obtidos a partir do endpoint de descoberta.", + "INFO": { + "ISSUER": "Emissor", + "CLIENTID": "ID do Cliente" + }, + "CURRENT": "Configuração Atual", + "TOKENSECTIONTITLE": "Opções de Token de Autenticação", + "REDIRECTSECTIONTITLE": "Configurações de Redirecionamento", + "REDIRECTTITLE": "Especifique as URIs para onde o login será redirecionado.", + "POSTREDIRECTTITLE": "Esta é a URI de redirecionamento após o logout.", + "REDIRECTDESCRIPTIONWEB": "URIs de redirecionamento devem começar com https://. http:// é válido apenas com o modo de desenvolvimento habilitado.", + "REDIRECTDESCRIPTIONNATIVE": "URIs de redirecionamento devem começar com seu próprio protocolo, http://127.0.0.1, http://[::1] ou http://localhost.", + "REDIRECTNOTVALID": "Esta URI de redirecionamento não é válida.", + "COMMAORENTERSEPERATION": "separar com ↵", + "TYPEREQUIRED": "O tipo é obrigatório.", + "TITLE": "Configuração OIDC", + "CLIENTID": "ID do Cliente", + "CLIENTSECRET": "Segredo do Cliente", + "CLIENTSECRET_NOSECRET": "Com o fluxo de autenticação escolhido, nenhum segredo é necessário e, portanto, não está disponível.", + "CLIENTSECRET_DESCRIPTION": "Mantenha o segredo do cliente em um local seguro, pois ele desaparecerá assim que o diálogo for fechado.", + "REGENERATESECRET": "Regenerar Segredo do Cliente", + "DEVMODE": "Modo de Desenvolvimento", + "DEVMODEDESC": "Atenção: Com o modo de desenvolvimento habilitado, as URIs de redirecionamento não serão validadas.", + "SKIPNATIVEAPPSUCCESSPAGE": "Pular Página de Sucesso de Login", + "SKIPNATIVEAPPSUCCESSPAGE_DESCRIPTION": "Pule a página de sucesso após o login para este aplicativo nativo.", + "REDIRECT": "URIs de Redirecionamento", + "REDIRECTSECTION": "URIs de Redirecionamento", + "POSTLOGOUTREDIRECT": "URIs de Pós-Logout", + "RESPONSESECTION": "Tipos de Resposta", + "GRANTSECTION": "Tipos de Concessão", + "GRANTTITLE": "Selecione os tipos de concessão. Observação: O tipo Implícito está disponível apenas para aplicativos baseados em navegador.", + "APPTYPE": { + "0": "Web", + "1": "Agente de Usuário", + "2": "Nativo" + }, + "RESPONSETYPE": "Tipos de Resposta", + "RESPONSE": { + "0": "Código", + "1": "ID Token", + "2": "Token-ID Token" + }, + "REFRESHTOKEN": "Token de Atualização", + "GRANTTYPE": "Tipos de Concessão", + "GRANT": { + "0": "Código de Autorização", + "1": "Implícito", + "2": "Token de Atualização", + "3": "Código do Dispositivo" + }, + "AUTHMETHOD": { + "0": "Básico", + "1": "Post", + "2": "Nenhum", + "3": "JWT de Chave Privada" + }, + "TOKENTYPE": "Tipo de Token de Autenticação", + "TOKENTYPE0": "Token de Portador", + "TOKENTYPE1": "JWT", + "UNSECUREREDIRECT": "Espero que você saiba o que está fazendo.", + "OVERVIEWSECTION": "Visão Geral", + "OVERVIEWTITLE": "Agora você terminou. Revise sua configuração.", + "ACCESSTOKENROLEASSERTION": "Adicionar funções do usuário ao token de acesso", + "ACCESSTOKENROLEASSERTION_DESCRIPTION": "Se selecionado, as funções solicitadas do usuário autenticado serão adicionadas ao token de acesso.", + "IDTOKENROLEASSERTION": "Funções do usuário no ID Token", + "IDTOKENROLEASSERTION_DESCRIPTION": "Se selecionado, as funções solicitadas do usuário autenticado serão adicionadas ao ID token.", + "IDTOKENUSERINFOASSERTION": "Informações do usuário no ID Token", + "IDTOKENUSERINFOASSERTION_DESCRIPTION": "Permite que os clientes obtenham claims de perfil, e-mail, telefone e endereço do ID token.", + "CLOCKSKEW": "Permite que os clientes lidem com a discrepância de tempo do OP e do cliente. A duração (0-5s) será adicionada ao claim exp e subtraída de iat, auth_time e nbf.", + "RECOMMENDED": "recomendado", + "NOTRECOMMENDED": "não recomendado", + "SELECTION": { + "APPTYPE": { + "WEB": { + "TITLE": "Web", + "DESCRIPTION": "Aplicações da Web regulares como .net, PHP, Node.js, Java, etc." + }, + "NATIVE": { + "TITLE": "Nativo", + "DESCRIPTION": "Aplicativos móveis, desktop, dispositivos inteligentes, etc." + }, + "USERAGENT": { + "TITLE": "Agente de Usuário", + "DESCRIPTION": "Aplicativos de página única (SPA) e, em geral, todos os frameworks JS executados em navegadores" + } + } + } + }, + "API": { + "INFO": { + "CLIENTID": "ID do Cliente" + }, + "REGENERATESECRET": "Regenerar Segredo do Cliente", + "SELECTION": { + "TITLE": "API", + "DESCRIPTION": "APIs em geral" + }, + "AUTHMETHOD": { + "0": "Básico", + "1": "JWT de Chave Privada" + } + }, + "SAML": { + "SELECTION": { + "TITLE": "SAML", + "DESCRIPTION": "Aplicativos SAML" + }, + "CONFIGSECTION": "Configuração SAML", + "URL": "URL onde o arquivo de Metadados está localizado", + "OR": "ou", + "XML": "Carregar XML de Metadados", + "METADATA": "Metadados", + "METADATAFROMFILE": "Metadados do Arquivo" + }, + "AUTHMETHODS": { + "CODE": { + "TITLE": "Código", + "DESCRIPTION": "Trocar o código de autorização pelos tokens" + }, + "PKCE": { + "TITLE": "PKCE", + "DESCRIPTION": "Usar um hash aleatório em vez de um segredo de cliente estático para maior segurança" + }, + "POST": { + "TITLE": "POST", + "DESCRIPTION": "Enviar client_id e client_secret como parte do formulário" + }, + "PK_JWT": { + "TITLE": "JWT de Chave Privada", + "DESCRIPTION": "Usar uma chave privada para autorizar seu aplicativo" + }, + "BASIC": { + "TITLE": "Básico", + "DESCRIPTION": "Autenticação com Nome de Usuário e Senha" + }, + "IMPLICIT": { + "TITLE": "Implícito", + "DESCRIPTION": "Obter os tokens diretamente do ponto de extremidade de autorização" + }, + "DEVICECODE": { + "TITLE": "Código do Dispositivo", + "DESCRIPTION": "Autorizar o dispositivo em um computador ou smartphone." + }, + "CUSTOM": { + "TITLE": "Personalizado", + "DESCRIPTION": "Sua configuração não corresponde a nenhuma outra opção." + } + }, + "TOAST": { + "REACTIVATED": "Aplicativo reativado.", + "DEACTIVATED": "Aplicativo desativado.", + "OIDCUPDATED": "Aplicativo atualizado.", + "APIUPDATED": "Aplicativo atualizado.", + "UPDATED": "Aplicativo atualizado.", + "CREATED": "Aplicativo criado.", + "CLIENTSECRETREGENERATED": "segredo do cliente gerado.", + "DELETED": "Aplicativo excluído.", + "CONFIGCHANGED": "Alterações detectadas!" + } + }, + "GENDERS": { + "0": "Desconhecido", + "1": "Feminino", + "2": "Masculino", + "3": "Outro" + }, + "LANGUAGES": { + "de": "Deutsch", + "en": "English", + "es": "Español", + "fr": "Français", + "it": "Italiano", + "ja": "日本語", + "pl": "Polski", + "zh": "简体中文", + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" + }, + "MEMBER": { + "ADD": "Adicionar um Gerente", + "CREATIONTYPE": "Tipo de Criação", + "CREATIONTYPES": { + "3": "IAM", + "2": "Organização", + "0": "Projeto Próprio", + "1": "Projeto Concedido", + "4": "Projeto" + }, + "EDITROLE": "Editar funções", + "EDITFOR": "Editar as funções para o usuário: {{value}}", + "DIALOG": { + "DELETE_TITLE": "Remover Gerente", + "DELETE_DESCRIPTION": "Você está prestes a remover um gerente. Tem certeza?" + } + }, + "ROLESLABEL": "Funções", + "GRANTS": { + "TITLE": "Autorizações", + "DESC": "Estas são todas as autorizações na sua organização.", + "DELETE": "Excluir Autorização", + "EMPTY": "Nenhuma autorização encontrada", + "ADD": "Criar Autorização", + "ADD_BTN": "Novo", + "PROJECT": { + "TITLE": "Autorização", + "DESCRIPTION": "Defina as autorizações para o projeto especificado. Observe que você só pode ver entradas de projetos e usuários para os quais você tem permissão." + }, + "USER": { + "TITLE": "Autorização", + "DESCRIPTION": "Defina as autorizações para o usuário especificado. Observe que você só pode ver entradas de projetos e usuários para os quais você tem permissão." + }, + "CREATE": { + "TITLE": "Criar autorização", + "DESCRIPTION": "Pesquise a organização, o projeto e as funções correspondentes." + }, + "EDIT": { + "TITLE": "Alterar autorização" + }, + "DETAIL": { + "TITLE": "Detalhes da Autorização", + "DESCRIPTION": "Aqui você pode ver todos os detalhes da autorização." + }, + "TOAST": { + "UPDATED": "Autorização atualizada.", + "REMOVED": "Autorização removida", + "BULKREMOVED": "Autorizações removidas." + }, + "DIALOG": { + "DELETE_TITLE": "Excluir autorização", + "DELETE_DESCRIPTION": "Você está prestesa excluir uma autorização. Deseja continuar?", + "BULK_DELETE_TITLE": "Excluir autorizações", + "BULK_DELETE_DESCRIPTION": "Você está prestes a excluir várias autorizações. Deseja continuar?" + } + }, + "CHANGES": { + "LISTTITLE": "Últimas Alterações", + "BOTTOM": "Você chegou ao final da lista.", + "LOADMORE": "Carregar mais", + "ORG": { + "TITLE": "Atividade", + "DESCRIPTION": "Aqui você pode ver os eventos mais recentes que geraram uma alteração na organização." + }, + "PROJECT": { + "TITLE": "Atividade", + "DESCRIPTION": "Aqui você pode ver os eventos mais recentes que geraram uma alteração no projeto." + }, + "USER": { + "TITLE": "Atividade", + "DESCRIPTION": "Aqui você pode ver os eventos mais recentes que geraram uma alteração no usuário." + } + } +} \ No newline at end of file diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json index 6c78f6454..a9527fb16 100644 --- a/console/src/assets/i18n/zh.json +++ b/console/src/assets/i18n/zh.json @@ -1040,7 +1040,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "SMTP": { "TITLE": "SMTP 设置", @@ -1239,7 +1241,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "KEYS": { "emailVerificationDoneText": "电子邮件验证完成", @@ -1338,6 +1342,8 @@ "ALLOWREGISTER_DESC": "如果选择了该选项,登录中会出现一个用于注册用户的附加步骤。", "FORCEMFA": "强制使用 MFA", "FORCEMFA_DESC": "如果选择该选项,用户必须配置第二身份认证登录因素。", + "FORCEMFALOCALONLY": "对本地用户强制执行 MFA", + "FORCEMFALOCALONLY_DESC": "如果选择该选项,本地经过身份验证的用户必须配置第二个登录因素。", "HIDEPASSWORDRESET": "隐藏密码重置按钮", "HIDEPASSWORDRESET_DESC": "如果选择该选项,则用户无法在登录过程中重置其密码。", "HIDELOGINNAMESUFFIX": "隐藏登录名后缀", @@ -1505,13 +1511,11 @@ "SEL_PROJECT": "搜索项目", "SEL_ROLES": "选择要添加到授权中的角色", "SEL_USER": "选择一个或多个用户", - "SEL_ORG": "选择一个组织", - "SEL_ORG_DESC": "输入完整的域以指定要授予的组织。", - "ORG_TITLE": "组织", + "SEL_ORG": "搜索组织", + "SEL_ORG_DESC": "搜索要授予的组织", "ORG_DESCRIPTION": "您即将授予组织 {{name}} 的用户。", "ORG_DESCRIPTION_DESC": "切换上面标题中的上下文以授予另一个组织的用户。", - "SEL_ORG_FORMFIELD": "完整域名", - "SEL_ORG_BUTTON": "搜索组织", + "SEL_ORG_FORMFIELD": "组织", "FOR_ORG": "授予组织:" }, "DETAIL": { @@ -1787,6 +1791,8 @@ "DELETE": "删除", "DELETE_TITLE": "删除 IDP", "DELETE_DESCRIPTION": "您即将删除身份提供者。由此产生的变化是不可撤销的。你真的想这样做吗?", + "REMOVE_WARN_TITLE": "删除国内流离失所者", + "REMOVE_WARN_DESCRIPTION": "您即将删除身份提供者。这将为您的用户删除可用 IDP 的选择,并且已经注册的用户将无法再次登录。您确定要继续吗?", "DELETE_SELECTION_TITLE": "删除 IDP", "DELETE_SELECTION_DESCRIPTION": "您即将删除身份提供者。由此产生的变化是不可撤销的。你真的想这样做吗?", "EMPTY": "没有可用的 IDP", @@ -2097,7 +2103,9 @@ "ja": "日本語", "pl": "Polski", "zh": "简体中文", - "bg": "Български" + "bg": "Български", + "pt": "Portuguese", + "mk": "Македонски" }, "MEMBER": { "ADD": "添加管理者", diff --git a/console/yarn.lock b/console/yarn.lock new file mode 100644 index 000000000..553e814e7 --- /dev/null +++ b/console/yarn.lock @@ -0,0 +1,9721 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@2.2.1", "@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@angular-devkit/architect@0.1601.4": + version "0.1601.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1601.4.tgz#9fc88461cb65e28508067d93acc1aba69ca7a9ec" + integrity sha512-OOSbNlDy+Q3jY0oFHaq8kkna9HYI1zaS8IHeCIDP6T/ZIAVad4+HqXAL4SKQrKJikkoBQv1Z/eaDBL5XPFK9Bw== + dependencies: + "@angular-devkit/core" "16.1.4" + rxjs "7.8.1" + +"@angular-devkit/build-angular@^16.1.1": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-16.1.4.tgz#81d5430b2d694b454553669f75b2732dc49ee870" + integrity sha512-LiHM7R20fTHg/eM+Iabotj08edP5wVBQahRfVNLxERo8X6VJgSjVChnsh3AQJkRywlGuFe20AOQYpyLyN367Ug== + dependencies: + "@ampproject/remapping" "2.2.1" + "@angular-devkit/architect" "0.1601.4" + "@angular-devkit/build-webpack" "0.1601.4" + "@angular-devkit/core" "16.1.4" + "@babel/core" "7.22.5" + "@babel/generator" "7.22.7" + "@babel/helper-annotate-as-pure" "7.22.5" + "@babel/helper-split-export-declaration" "7.22.5" + "@babel/plugin-proposal-async-generator-functions" "7.20.7" + "@babel/plugin-transform-async-to-generator" "7.22.5" + "@babel/plugin-transform-runtime" "7.22.5" + "@babel/preset-env" "7.22.5" + "@babel/runtime" "7.22.5" + "@babel/template" "7.22.5" + "@discoveryjs/json-ext" "0.5.7" + "@ngtools/webpack" "16.1.4" + "@vitejs/plugin-basic-ssl" "1.0.1" + ansi-colors "4.1.3" + autoprefixer "10.4.14" + babel-loader "9.1.2" + babel-plugin-istanbul "6.1.1" + browserslist "^4.21.5" + cacache "17.1.3" + chokidar "3.5.3" + copy-webpack-plugin "11.0.0" + critters "0.0.19" + css-loader "6.8.1" + esbuild-wasm "0.17.19" + fast-glob "3.2.12" + https-proxy-agent "5.0.1" + inquirer "8.2.4" + jsonc-parser "3.2.0" + karma-source-map-support "1.4.0" + less "4.1.3" + less-loader "11.1.0" + license-webpack-plugin "4.0.2" + loader-utils "3.2.1" + magic-string "0.30.0" + mini-css-extract-plugin "2.7.6" + mrmime "1.0.1" + open "8.4.2" + ora "5.4.1" + parse5-html-rewriting-stream "7.0.0" + picomatch "2.3.1" + piscina "3.2.0" + postcss "8.4.24" + postcss-loader "7.3.2" + resolve-url-loader "5.0.0" + rxjs "7.8.1" + sass "1.63.2" + sass-loader "13.3.1" + semver "7.5.3" + source-map-loader "4.0.1" + source-map-support "0.5.21" + terser "5.17.7" + text-table "0.2.0" + tree-kill "1.2.2" + tslib "2.5.3" + vite "4.3.9" + webpack "5.86.0" + webpack-dev-middleware "6.1.1" + webpack-dev-server "4.15.0" + webpack-merge "5.9.0" + webpack-subresource-integrity "5.1.0" + optionalDependencies: + esbuild "0.17.19" + +"@angular-devkit/build-webpack@0.1601.4": + version "0.1601.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1601.4.tgz#170534d977b19e439687772a0106bcebe3fbc0d8" + integrity sha512-GC1y//ScAYbYQ68Wri2QgTEekC4hRxBC+xEkYL9OFiAMQ4mcN+eYvbkQBX8enJwDMXpkYfLR6VV8cChjAVYIgg== + dependencies: + "@angular-devkit/architect" "0.1601.4" + rxjs "7.8.1" + +"@angular-devkit/core@16.1.4": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-16.1.4.tgz#033ff3ab4d024ee3d8f4c6f809eed10d716ad0ab" + integrity sha512-WCAzNi9LxpFIi2WVPaJQd2kHPqCnCexWzUZN05ltJuBGCQL1O+LgRHGwnQ4WZoqmrF5tcWt2a3GFtJ3DgMc1hw== + dependencies: + ajv "8.12.0" + ajv-formats "2.1.1" + jsonc-parser "3.2.0" + rxjs "7.8.1" + source-map "0.7.4" + +"@angular-devkit/schematics@16.1.4": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-16.1.4.tgz#91d4d82ee273dd7f24c17b9c7fbbfff11d7cab63" + integrity sha512-yjRgwHAfFaeuimgbQtjwSUyXzEHpMSdTRb2zg+TOp6skoGvHOG8xXFJ7DjBkSMeAQdFF0fkxhPS9YmlxqNc+7A== + dependencies: + "@angular-devkit/core" "16.1.4" + jsonc-parser "3.2.0" + magic-string "0.30.0" + ora "5.4.1" + rxjs "7.8.1" + +"@angular-eslint/builder@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/builder/-/builder-16.0.1.tgz#f5db761dedec0d412367bb8d64d5042e09bbeca7" + integrity sha512-yjFltV+r3YjisVjASMPmWB/ASz39wdh0q5g0l6/4G+8yaxl6hEYs5o0ZOGeGdTFstCql8FGY+QKwKgsq9Ec4QQ== + dependencies: + "@nx/devkit" "16.0.2" + nx "16.0.2" + +"@angular-eslint/bundled-angular-compiler@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.0.1.tgz#a1706204e2b5a06355f71c2465a79f4ded05771e" + integrity sha512-amvTgKHtZoygivW3LAYZ9qjLWsXM7/7eaRvaHdmAEdjyFnYQZ7UbWMPSQNz1mlW/AzTFvk9lGGQORglNOSDnww== + +"@angular-eslint/eslint-plugin-template@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.0.1.tgz#304af27fb7621584a4943c80d8103e4d82fc1646" + integrity sha512-1hyfs+Iq7K2x3mDDE4985d8vDcMyknbE9HKHKUtRLfLKC9gnV3N5d4+UeySQ7Rrjvgzkc1g9qHADyuhwRWpDSA== + dependencies: + "@angular-eslint/bundled-angular-compiler" "16.0.1" + "@angular-eslint/utils" "16.0.1" + "@typescript-eslint/type-utils" "5.59.2" + "@typescript-eslint/utils" "5.59.2" + aria-query "5.1.3" + axobject-query "3.1.1" + +"@angular-eslint/eslint-plugin@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin/-/eslint-plugin-16.0.1.tgz#759df2d844478756d68ddc3db4e320d381c0ce7e" + integrity sha512-CM9keS9cH1QAfSVfsvhw/oGCZcP/D8gfekWwVNjN/uEMEAak0czn1KOG7JQkE36NXOGtwCpTspMi1aa9CVKo9g== + dependencies: + "@angular-eslint/utils" "16.0.1" + "@typescript-eslint/utils" "5.59.2" + +"@angular-eslint/schematics@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/schematics/-/schematics-16.0.1.tgz#db5be27b9cb0de97eb66e2c8b078e377e331acb2" + integrity sha512-1oJJEWVbgPkNK1E8rAJfrgxzNWWzJKv3frTHeAm8gvZ7GftYhHjDcrcnxLWrYNxb9+q8Awi0hvGta/4HROmmnA== + dependencies: + "@angular-eslint/eslint-plugin" "16.0.1" + "@angular-eslint/eslint-plugin-template" "16.0.1" + "@nx/devkit" "16.0.2" + ignore "5.2.4" + nx "16.0.2" + strip-json-comments "3.1.1" + tmp "0.2.1" + +"@angular-eslint/template-parser@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/template-parser/-/template-parser-16.0.1.tgz#e97867d2673afa9291190f402df58981aa4fab01" + integrity sha512-x0+SwSeqa3TiVZan6fE5grHsCkjGqU+zAS2DB6wAw5pyvgNAIjrI4cZEQ8pkgHfXe5tuumTKztlkpisah5s/hg== + dependencies: + "@angular-eslint/bundled-angular-compiler" "16.0.1" + eslint-scope "^7.0.0" + +"@angular-eslint/utils@16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@angular-eslint/utils/-/utils-16.0.1.tgz#d71332111b3dcdc96dd207344956b243ff28b3b3" + integrity sha512-2xnJuhIrMZEYK6UyBym6FaFXZgopIIbqfQ4sAtMWY6zYkCEsVUvx5qKIrsnXAwvpDQrv0WiMXteqi/5ICpVMZQ== + dependencies: + "@angular-eslint/bundled-angular-compiler" "16.0.1" + "@typescript-eslint/utils" "5.59.2" + +"@angular/animations@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-16.1.4.tgz#4d3ed2aa0849ef8589fe39d4f531a5d9c6c35e6a" + integrity sha512-QdqmnMEYsrZK1BB+/TGteyoQVRwIpRdBP4Jg+hX/BDhVpt35dptSwvNZj7+9zoYLwNo5DuGlttljEaLOs1UcUw== + dependencies: + tslib "^2.3.0" + +"@angular/cdk@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-16.1.4.tgz#91c61aca92b037bd9c7e6def2c48c89f7e5211e8" + integrity sha512-05m0+NoAkV5O15GUEX2GQLySe8iC6P0GXVqUjLipdGmZ2/pNndJ/DGbqkX8dAAo/Z3ss2TEyRNYMOJdLIjV5vw== + dependencies: + tslib "^2.3.0" + optionalDependencies: + parse5 "^7.1.2" + +"@angular/cli@^16.1.1": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-16.1.4.tgz#b32de345b6fdb4e975f957b0f9cbcafdcf184f8a" + integrity sha512-coSOLVLpOCOD5q9K9EAFFMrTES+HtdJiLy/iI9kdKNCKWUJpm8/svZ3JZOej3vPxYEp0AokXNOwORQnX21/qZQ== + dependencies: + "@angular-devkit/architect" "0.1601.4" + "@angular-devkit/core" "16.1.4" + "@angular-devkit/schematics" "16.1.4" + "@schematics/angular" "16.1.4" + "@yarnpkg/lockfile" "1.1.0" + ansi-colors "4.1.3" + ini "4.1.1" + inquirer "8.2.4" + jsonc-parser "3.2.0" + npm-package-arg "10.1.0" + npm-pick-manifest "8.0.1" + open "8.4.2" + ora "5.4.1" + pacote "15.2.0" + resolve "1.22.2" + semver "7.5.3" + symbol-observable "4.0.0" + yargs "17.7.2" + +"@angular/common@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-16.1.4.tgz#2c09b36c08e386cd75d6ceea9f3c67105a2347ae" + integrity sha512-SDA8GZVY0nXCJaNUy13L22jAKuk1LZgQ6QzqOpqQc50C25bfBQbYv68PKjHCjQ62VxGKnDSTT85xCMNx+y/U4g== + dependencies: + tslib "^2.3.0" + +"@angular/compiler-cli@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-16.1.4.tgz#344c81781ed9562fd80b2e0b64edc953ac48c57a" + integrity sha512-JerJOZeOLaHFHrfWMm4m9tEw+MdNNIMPj3TSauJ6uZPbFokGeqS2GsUBMjuQlwh5xY4duh1HtRsohvshpl306A== + dependencies: + "@babel/core" "7.22.5" + "@jridgewell/sourcemap-codec" "^1.4.14" + chokidar "^3.0.0" + convert-source-map "^1.5.1" + reflect-metadata "^0.1.2" + semver "^7.0.0" + tslib "^2.3.0" + yargs "^17.2.1" + +"@angular/compiler@9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.0.tgz#87e0bef4c369b6cadae07e3a4295778fc93799d5" + integrity sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ== + +"@angular/compiler@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-16.1.4.tgz#6b42ce34c0388bc1d88a3f37b55504a3428e22c8" + integrity sha512-5iKx8g+6/LtiRhbqMS2Jw1AshFUb4M8LO9WQKfRoE+5mZrDOYkAQYgOlAO7fk0mOCXeZcHJBbq2nuwDfwsZIiw== + dependencies: + tslib "^2.3.0" + +"@angular/core@9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.0.0.tgz#227dc53e1ac81824f998c6e76000b7efc522641e" + integrity sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w== + +"@angular/core@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-16.1.4.tgz#d9119e4d9c226e723ea5acc8e4a078158f1a35da" + integrity sha512-eWs++peAp+Lm2SHGfMsHAye2IOmlDKkVJ4dFf4TaZXW+AEev3FXKXLFp+dBUq8YkCKly7iAV26NXEUBOFFtplQ== + dependencies: + tslib "^2.3.0" + +"@angular/forms@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-16.1.4.tgz#fcf4c8ab23c997e29bda146da6a821b7db1f9973" + integrity sha512-JLhO7gM0WyTfr6tEWZMiCGikWLgaC/a2+tuxWsSlXUjlrbE4DyLzSAA6JqyDCFTvm9B/QzRPDfgExLTTZJY4eQ== + dependencies: + tslib "^2.3.0" + +"@angular/language-service@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-16.1.4.tgz#9d1e9872dc410726e8a12ace503bd3e1c69b7488" + integrity sha512-FmasGUt77+GS2AFspVJR8Sg0NNlxCJJKHCHO4cch2fKXnwLZxd4aeHU0ttlVCA/hTFN50+03S3CBvru25L+74A== + +"@angular/material-moment-adapter@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/material-moment-adapter/-/material-moment-adapter-16.1.4.tgz#59ad0d22d9f31d39fbaaaacf52ce40ff2f45cb2d" + integrity sha512-3yoYZdGALqiZD2F+pcKMzygHvpFYObjXBi0aVSJ+15bNvAWayfUYT7RnWVuDMt0a5lqY0L+u9aJbQj0rD4jDYA== + dependencies: + tslib "^2.3.0" + +"@angular/material@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-16.1.4.tgz#8086e982a54aff0aec7f9b7a2e5e790161fa5e13" + integrity sha512-1SKWB14J+IorRL6uzq4a9cBLpVOMONTzso05LoVLGKrmtMCL5cRYLM/otT0IjY+oqG/fnTpsYDwV7E6n7AljeA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/auto-init" "15.0.0-canary.b994146f6.0" + "@material/banner" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/button" "15.0.0-canary.b994146f6.0" + "@material/card" "15.0.0-canary.b994146f6.0" + "@material/checkbox" "15.0.0-canary.b994146f6.0" + "@material/chips" "15.0.0-canary.b994146f6.0" + "@material/circular-progress" "15.0.0-canary.b994146f6.0" + "@material/data-table" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dialog" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/drawer" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/fab" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/floating-label" "15.0.0-canary.b994146f6.0" + "@material/form-field" "15.0.0-canary.b994146f6.0" + "@material/icon-button" "15.0.0-canary.b994146f6.0" + "@material/image-list" "15.0.0-canary.b994146f6.0" + "@material/layout-grid" "15.0.0-canary.b994146f6.0" + "@material/line-ripple" "15.0.0-canary.b994146f6.0" + "@material/linear-progress" "15.0.0-canary.b994146f6.0" + "@material/list" "15.0.0-canary.b994146f6.0" + "@material/menu" "15.0.0-canary.b994146f6.0" + "@material/menu-surface" "15.0.0-canary.b994146f6.0" + "@material/notched-outline" "15.0.0-canary.b994146f6.0" + "@material/radio" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/segmented-button" "15.0.0-canary.b994146f6.0" + "@material/select" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/slider" "15.0.0-canary.b994146f6.0" + "@material/snackbar" "15.0.0-canary.b994146f6.0" + "@material/switch" "15.0.0-canary.b994146f6.0" + "@material/tab" "15.0.0-canary.b994146f6.0" + "@material/tab-bar" "15.0.0-canary.b994146f6.0" + "@material/tab-indicator" "15.0.0-canary.b994146f6.0" + "@material/tab-scroller" "15.0.0-canary.b994146f6.0" + "@material/textfield" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tooltip" "15.0.0-canary.b994146f6.0" + "@material/top-app-bar" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.3.0" + +"@angular/platform-browser-dynamic@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.1.4.tgz#95c2d963439ef5a78e9e5742e8dd77473e80690d" + integrity sha512-OIszPs3NLCZWL8BEvn458JotNMdXPGyEVToNa2cEVgtakVxkhrhmoFlwJTWJN4GRkHNL5h2Vb0JLEYICwr7sgg== + dependencies: + tslib "^2.3.0" + +"@angular/platform-browser@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-16.1.4.tgz#284f01179aee615ff65c5ce67c68006daded1397" + integrity sha512-eQ1dBh/6ZwJVeiNGrcW6ePFmWeS+Oheu1RpuZSsvM/fI6qfsZE+or9IJ61SFvsMs65SbrO90Akc+ZXmpEidPdA== + dependencies: + tslib "^2.3.0" + +"@angular/router@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-16.1.4.tgz#53cd876f52e0cb36054416d5671aa90cc7ff7598" + integrity sha512-ooAK7XsY7fLW80htej9jHmct37biK77aNApCdiY+KlLdd45x//ObGxRYXcSSyvs7mRS0AMTGuA/G7/5AMcqcZg== + dependencies: + tslib "^2.3.0" + +"@angular/service-worker@^16.1.2": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-16.1.4.tgz#94e4b5112f7271f1e02b1fd6fbb9b3d12f45f975" + integrity sha512-ShP3nD3UOER1gf6daYkQqwfKCz/2/NhzsJIRxL9AonBB4qLDU/MzYWC3nts43+AESZfdibnF1LCWkvUmceqvGA== + dependencies: + tslib "^2.3.0" + +"@assemblyscript/loader@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" + integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg== + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + +"@babel/compat-data@^7.21.5": + version "7.21.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.7.tgz#61caffb60776e49a57ba61a88f02bedd8714f6bc" + integrity sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA== + +"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.6.tgz#15606a20341de59ba02cd2fcc5086fcbe73bf544" + integrity sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg== + +"@babel/core@7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.5.tgz#d67d9747ecf26ee7ecd3ebae1ee22225fe902a89" + integrity sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helpers" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.5" + "@babel/types" "^7.22.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@^7.12.3": + version "7.21.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.8.tgz#2a8c7f0f53d60100ba4c32470ba0281c92aa9aa4" + integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.5" + "@babel/helper-compilation-targets" "^7.21.5" + "@babel/helper-module-transforms" "^7.21.5" + "@babel/helpers" "^7.21.5" + "@babel/parser" "^7.21.8" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.5" + "@babel/types" "^7.21.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/generator@7.22.7", "@babel/generator@^7.22.5", "@babel/generator@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.7.tgz#a6b8152d5a621893f2c9dacf9a4e286d520633d5" + integrity sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ== + dependencies: + "@babel/types" "^7.22.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/generator@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.5.tgz#c0c0e5449504c7b7de8236d99338c3e2a340745f" + integrity sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w== + dependencies: + "@babel/types" "^7.21.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@7.22.5", "@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz#a3f4758efdd0190d8927fcffd261755937c71878" + integrity sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-compilation-targets@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz#631e6cc784c7b660417421349aac304c94115366" + integrity sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w== + dependencies: + "@babel/compat-data" "^7.21.5" + "@babel/helper-validator-option" "^7.21.0" + browserslist "^4.21.3" + lru-cache "^5.1.1" + semver "^6.3.0" + +"@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz#e30d61abe9480aa5a83232eb31c111be922d2e52" + integrity sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-validator-option" "^7.22.5" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + browserslist "^4.21.9" + lru-cache "^5.1.1" + +"@babel/helper-create-class-features-plugin@^7.22.5": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.6.tgz#58564873c889a6fea05a538e23f9f6d201f10950" + integrity sha512-iwdzgtSiBxF6ni6mzVnZCF3xt5qE6cEA0J7nFt8QOAWZ0zjCFceEgpn3vtb2V7WFR6QzP2jmIFOHMTRo7eNJjQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + +"@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.21.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.8.tgz#a7886f61c2e29e21fd4aaeaf1e473deba6b571dc" + integrity sha512-zGuSdedkFtsFHGbexAvNuipg1hbtitDLo2XE8/uf6Y9sOQV1xsYX/2pNbtedp/X0eU1pIt+kGvaqHCowkRbS5g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.3.1" + semver "^6.3.0" + +"@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.6.tgz#87afd63012688ad792de430ceb3b6dc28e4e7a40" + integrity sha512-nBookhLKxAWo/TUCmhnaEJyLz2dekjQvv5SRpE9epWQBcpedWLKt8aZdsuT9XV5ovzR3fENLjRXVT0GsSlGGhA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + regexpu-core "^5.3.1" + +"@babel/helper-define-polyfill-provider@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz#af1429c4a83ac316a6a8c2cc8ff45cb5d2998d3a" + integrity sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz#c769afefd41d171836f7cb63e295bedf689d48ba" + integrity sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ== + +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== + dependencies: + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" + integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== + dependencies: + "@babel/types" "^7.21.4" + +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-transforms@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz#d937c82e9af68d31ab49039136a222b17ac0b420" + integrity sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw== + dependencies: + "@babel/helper-environment-visitor" "^7.21.5" + "@babel/helper-module-imports" "^7.21.4" + "@babel/helper-simple-access" "^7.21.5" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.5" + "@babel/types" "^7.21.5" + +"@babel/helper-module-transforms@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz#0f65daa0716961b6e96b164034e737f60a80d2ef" + integrity sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" + integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== + +"@babel/helper-plugin-utils@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-remap-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz#14a38141a7bf2165ad38da61d61cf27b43015da2" + integrity sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-wrap-function" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-replace-supers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz#71bc5fb348856dea9fdc4eafd7e2e49f585145dc" + integrity sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-simple-access@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz#d697a7971a5c39eac32c7e63c0921c06c8a249ee" + integrity sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg== + dependencies: + "@babel/types" "^7.21.5" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz#88cf11050edb95ed08d596f7a044462189127a08" + integrity sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.22.5", "@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz#2b3eea65443c6bdc31c22d037c65f6d323b6b2bd" + integrity sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w== + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-option@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" + integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" + integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" + +"@babel/helper-wrap-function@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz#44d205af19ed8d872b4eefb0d2fa65f45eb34f06" + integrity sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw== + dependencies: + "@babel/helper-function-name" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helpers@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.5.tgz#5bac66e084d7a4d2d9696bdf0175a93f7fb63c08" + integrity sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA== + dependencies: + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.5" + "@babel/types" "^7.21.5" + +"@babel/helpers@^7.22.5": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.5", "@babel/parser@^7.21.8": + version "7.21.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.8.tgz#642af7d0333eab9c0ad70b14ac5e76dbde7bfdf8" + integrity sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA== + +"@babel/parser@^7.22.5", "@babel/parser@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" + integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" + integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" + integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" + +"@babel/plugin-proposal-async-generator-functions@7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" + integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-attributes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" + integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-async-generator-functions@^7.22.5": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz#053e76c0a903b72b573cb1ab7d6882174d460a1b" + integrity sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@7.22.5", "@babel/plugin-transform-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" + integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz#8bfc793b3a4b2742c0983fadc1480d843ecea31b" + integrity sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77" + integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba" + integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.22.5": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" + integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" + +"@babel/plugin-transform-destructuring@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz#d3aca7438f6c26c78cdd0b0ba920a336001b27cc" + integrity sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dotall-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" + integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" + integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dynamic-import@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e" + integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" + integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-export-namespace-from@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b" + integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" + integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-json-strings@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0" + integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-logical-assignment-operators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c" + integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-amd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" + integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa" + integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496" + integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ== + dependencies: + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/plugin-transform-modules-umd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" + integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-new-target@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" + integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381" + integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58" + integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1" + integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ== + dependencies: + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-optional-catch-binding@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333" + integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.5": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz#4bacfe37001fe1901117672875e931d439811564" + integrity sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" + integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-methods@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722" + integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32" + integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-regenerator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz#cd8a68b228a5f75fa01420e8cc2fc400f0fc32aa" + integrity sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + regenerator-transform "^0.15.1" + +"@babel/plugin-transform-reserved-words@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" + integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-runtime@7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz#ca975fb5e260044473c8142e1b18b567d33c2a3b" + integrity sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + babel-plugin-polyfill-corejs2 "^0.4.3" + babel-plugin-polyfill-corejs3 "^0.8.1" + babel-plugin-polyfill-regenerator "^0.5.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-sticky-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" + integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-template-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typeof-symbol@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" + integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-escapes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz#ce0c248522b1cb22c7c992d88301a5ead70e806c" + integrity sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-property-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" + integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" + integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" + integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/preset-env@7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.5.tgz#3da66078b181f3d62512c51cf7014392c511504e" + integrity sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A== + dependencies: + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.22.5" + "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.22.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.5" + "@babel/plugin-transform-async-to-generator" "^7.22.5" + "@babel/plugin-transform-block-scoped-functions" "^7.22.5" + "@babel/plugin-transform-block-scoping" "^7.22.5" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-class-static-block" "^7.22.5" + "@babel/plugin-transform-classes" "^7.22.5" + "@babel/plugin-transform-computed-properties" "^7.22.5" + "@babel/plugin-transform-destructuring" "^7.22.5" + "@babel/plugin-transform-dotall-regex" "^7.22.5" + "@babel/plugin-transform-duplicate-keys" "^7.22.5" + "@babel/plugin-transform-dynamic-import" "^7.22.5" + "@babel/plugin-transform-exponentiation-operator" "^7.22.5" + "@babel/plugin-transform-export-namespace-from" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-function-name" "^7.22.5" + "@babel/plugin-transform-json-strings" "^7.22.5" + "@babel/plugin-transform-literals" "^7.22.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.5" + "@babel/plugin-transform-member-expression-literals" "^7.22.5" + "@babel/plugin-transform-modules-amd" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.5" + "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.22.5" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5" + "@babel/plugin-transform-numeric-separator" "^7.22.5" + "@babel/plugin-transform-object-rest-spread" "^7.22.5" + "@babel/plugin-transform-object-super" "^7.22.5" + "@babel/plugin-transform-optional-catch-binding" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" + "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/plugin-transform-private-property-in-object" "^7.22.5" + "@babel/plugin-transform-property-literals" "^7.22.5" + "@babel/plugin-transform-regenerator" "^7.22.5" + "@babel/plugin-transform-reserved-words" "^7.22.5" + "@babel/plugin-transform-shorthand-properties" "^7.22.5" + "@babel/plugin-transform-spread" "^7.22.5" + "@babel/plugin-transform-sticky-regex" "^7.22.5" + "@babel/plugin-transform-template-literals" "^7.22.5" + "@babel/plugin-transform-typeof-symbol" "^7.22.5" + "@babel/plugin-transform-unicode-escapes" "^7.22.5" + "@babel/plugin-transform-unicode-property-regex" "^7.22.5" + "@babel/plugin-transform-unicode-regex" "^7.22.5" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.22.5" + babel-plugin-polyfill-corejs2 "^0.4.3" + babel-plugin-polyfill-corejs3 "^0.8.1" + babel-plugin-polyfill-regenerator "^0.5.0" + core-js-compat "^3.30.2" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" + integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/runtime@^7.8.4": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" + integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@7.22.5", "@babel/template@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/template@^7.18.10", "@babel/template@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/traverse@^7.20.5", "@babel/traverse@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.5.tgz#ad22361d352a5154b498299d523cf72998a4b133" + integrity sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw== + dependencies: + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.5" + "@babel/helper-environment-visitor" "^7.21.5" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.21.5" + "@babel/types" "^7.21.5" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/traverse@^7.22.5", "@babel/traverse@^7.22.6": + version "7.22.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e" + integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/types" "^7.22.5" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.4.4": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.5.tgz#18dfbd47c39d3904d5db3d3dc2cc80bedb60e5b6" + integrity sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q== + dependencies: + "@babel/helper-string-parser" "^7.21.5" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@babel/types@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@bufbuild/buf-darwin-arm64@1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.18.0-1.tgz#987712201ee03751e222a451b1c6d2d2513133d2" + integrity sha512-4iFChDoXAiuMZQoXpJoCSvCkcT7p1fmsY2N/+wTdODQbXAwqR8vQz19FPR2Jv5ukhd44LUi43nFsyQ2dWmeZeA== + +"@bufbuild/buf-darwin-x64@1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.18.0-1.tgz#9172a662cc66eb2d305db9233b344ae381ca84de" + integrity sha512-tuOnoCqFaUOj9dBuubEve5XGNkjL+zeCW7ETNgmArUlQobEkL2Fza5mi5Fqt90Ommfj1xpc4vaeNz1oSuU3dTw== + +"@bufbuild/buf-linux-aarch64@1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.18.0-1.tgz#4be09d3bc5feec481fedab0be4c9416d70cb88d3" + integrity sha512-QdYp89hlLVPPZYlaeVhE0swk5Ygncij1avVmvLQw99+lvaFlDu9zRQ0Jo7n1VjpZWdDhUd/thYWxSqSMJYLajA== + +"@bufbuild/buf-linux-x64@1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.18.0-1.tgz#fe2d61eb099d30de4c4903c3b1ddbed150ff41c2" + integrity sha512-9a6xv+OsYjhg5f1WHDtoXJVxG2j6awFi5cx9dkCPMODvFsll7skkwfkDngxKkibNU0aY6TxLoQXdf77eQwIWtQ== + +"@bufbuild/buf-win32-arm64@1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.18.0-1.tgz#4f6e8d76070e8eae689a0af4b0421241af995fd1" + integrity sha512-UP6KevD0cdxa4IJcDy31KC9sIIgxCWBP/K9uW+gBDLg2cNQBtVqlN8o65PJhsl9HB+p0/Y4pDi4i/jU8dXGH8g== + +"@bufbuild/buf-win32-x64@1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.18.0-1.tgz#b8b0d0c10ec8bbea944fdfb9fcd5638ffae59758" + integrity sha512-4OVbTwbQ1ZHGtITJw7hXYP2HinCWn3PN1ewCU+SCvynJTQ8vXQuVNlKZ2EmGl6aTUWdF3mSL/WPsRiG3fXhxfg== + +"@bufbuild/buf@^1.18.0-1": + version "1.18.0-1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.18.0-1.tgz#0ee0d09ff8ec738c482d7d7947dbc44ba5c9701f" + integrity sha512-Js6BEbjsfM+aFo2bUxfTs0B4htDbjWCKZ8+FHV6YYqiVsin6NGGQsXblJxwt4+16HLfSnrf41RRnwUaBwHqBzQ== + optionalDependencies: + "@bufbuild/buf-darwin-arm64" "1.18.0-1" + "@bufbuild/buf-darwin-x64" "1.18.0-1" + "@bufbuild/buf-linux-aarch64" "1.18.0-1" + "@bufbuild/buf-linux-x64" "1.18.0-1" + "@bufbuild/buf-win32-arm64" "1.18.0-1" + "@bufbuild/buf-win32-x64" "1.18.0-1" + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@ctrl/ngx-codemirror@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@ctrl/ngx-codemirror/-/ngx-codemirror-6.1.0.tgz#9324a56e4b709be9c515364d21e05e1d7589f009" + integrity sha512-73QeoNbnluZalWmNw+SOFctsE+oz0+4Bl9KhlJOIfbCPK/U6OIc+vQNr28hMAp15Y/Idde3LntTwLBDFW0bRVA== + dependencies: + "@types/codemirror" "^5.60.5" + tslib "^2.3.0" + +"@ctrl/tinycolor@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz#53fa5fe9c34faee89469e48f91d51a3766108bc8" + integrity sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ== + +"@discoveryjs/json-ext@0.5.7": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@esbuild/android-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd" + integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA== + +"@esbuild/android-arm@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d" + integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A== + +"@esbuild/android-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1" + integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww== + +"@esbuild/darwin-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276" + integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg== + +"@esbuild/darwin-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb" + integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw== + +"@esbuild/freebsd-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2" + integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ== + +"@esbuild/freebsd-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4" + integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ== + +"@esbuild/linux-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb" + integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg== + +"@esbuild/linux-arm@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a" + integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA== + +"@esbuild/linux-ia32@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a" + integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ== + +"@esbuild/linux-loong64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72" + integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ== + +"@esbuild/linux-mips64el@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289" + integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A== + +"@esbuild/linux-ppc64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7" + integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg== + +"@esbuild/linux-riscv64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09" + integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA== + +"@esbuild/linux-s390x@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829" + integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q== + +"@esbuild/linux-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4" + integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw== + +"@esbuild/netbsd-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462" + integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q== + +"@esbuild/openbsd-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691" + integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g== + +"@esbuild/sunos-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273" + integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg== + +"@esbuild/win32-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f" + integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag== + +"@esbuild/win32-ia32@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03" + integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw== + +"@esbuild/win32-x64@0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061" + integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA== + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== + +"@eslint/eslintrc@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" + integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.2" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.40.0": + version "8.40.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.40.0.tgz#3ba73359e11f5a7bd3e407f70b3528abfae69cec" + integrity sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA== + +"@gar/promisify@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + +"@grpc/grpc-js@^1.8.14": + version "1.8.14" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.14.tgz#4fe0f9917d6f094cf59245763c275442b182e9ad" + integrity sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A== + dependencies: + "@grpc/proto-loader" "^0.7.0" + "@types/node" ">=12.12.47" + +"@grpc/proto-loader@^0.7.0": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.7.tgz#d33677a77eea8407f7c66e2abd97589b60eb4b21" + integrity sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ== + dependencies: + "@types/long" "^4.0.1" + lodash.camelcase "^4.3.0" + long "^4.0.0" + protobufjs "^7.0.0" + yargs "^17.7.2" + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" + integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + +"@material/animation@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/animation/-/animation-15.0.0-canary.b994146f6.0.tgz#a64fc6151c58d0b840e27290cb6fa4887edfe738" + integrity sha512-kqqzG54tabYJ5VsBur5k1bqCFQCEpaW3hmLRMiSVVxRY7XgTt7qkuOOz48gs+MPqR6P8VIi6gFpuscV1+DWDhw== + dependencies: + tslib "^2.1.0" + +"@material/auto-init@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-15.0.0-canary.b994146f6.0.tgz#2081616bec5a896e8fe630803ef91db1406c81cb" + integrity sha512-8nLe/XeueJg5yyYx5e4UxWQXpTDyUhibKfyroGwnRKc8pdpOCOulHSOj/fIVGJAIbxkEJoebwMadWUNCjUhc9A== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/banner@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/banner/-/banner-15.0.0-canary.b994146f6.0.tgz#ea44f06cc34a4d9f5a8a0c818a14ad1023d1cf75" + integrity sha512-gJ4/VdP4dJgHP72Kdjy2f/UjHB45J4CuxoGvI0NIQYUjOSsr4kQiQHsjVgyEPZR/5wa7kBhM7/0mJ+zF7Ghv2A== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/button" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/base@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/base/-/base-15.0.0-canary.b994146f6.0.tgz#971ec50ca020168c1037a82fc2cb2aa14b6db9d1" + integrity sha512-rW2upYD5YjRFBL6DzYn3SCRhtvpEDkwplDS810e3vt71uLMRyqXyw4OQJH+Nab/t+32TFDtKNUphXIzwICXGDQ== + dependencies: + tslib "^2.1.0" + +"@material/button@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/button/-/button-15.0.0-canary.b994146f6.0.tgz#d2b57d4417b88c3eb42551806df5ef8eab2e8a0f" + integrity sha512-SMyqtsvJuCqpXBz2JgciuR6wddNJSGpTXUFxmLbGluBy5/hHm06JWlOFcUOxGDv46OdRGGrRfkg6A9JtvtsJsw== + dependencies: + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/card@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/card/-/card-15.0.0-canary.b994146f6.0.tgz#db05467020b87c21b07a647bc304d2bedcdcb378" + integrity sha512-WSggGon91HcDhJyatnYLFkoM9glkkeJjyjFDWrcJkwN1rdrPJU+GH+PNjvmArz5hGv9WkmjDjhOdAuPnL4Mb7g== + dependencies: + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/checkbox@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-15.0.0-canary.b994146f6.0.tgz#db66eca5402b1d3ee3f99d981871be41be279ada" + integrity sha512-pulRiwG9S/dS6WBG+GteODBltddFiL0Sb7HAqdzF2BTKNKv25q1ZIR3ftoEa09TNeWM88AOzTJ4aBHiADfJn2w== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/chips@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/chips/-/chips-15.0.0-canary.b994146f6.0.tgz#987a8d69748670d0bcdaba4c3d4272d6dc4d772d" + integrity sha512-3yJPj7x+eKLA4LMKG7aTWI+itAnKRVGOcniuR6aiXVy0OKr5asNuWNeZc9J0/VErjjxF3tdybDzDSPo01qPy9w== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/checkbox" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + safevalues "^0.3.4" + tslib "^2.1.0" + +"@material/circular-progress@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/circular-progress/-/circular-progress-15.0.0-canary.b994146f6.0.tgz#988c16c639c1c9187c7b9b5895174e807fef4478" + integrity sha512-6YUvGXdtZKJoE7AuovR4xk1aiWp/EDZ6j2U3TOeynd1assQQCg5XT4abqAoHtpJrRPaCFgUAp836HyiDVVuYug== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/progress-indicator" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/data-table@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/data-table/-/data-table-15.0.0-canary.b994146f6.0.tgz#f5c1687c5572469f1c0abdfbd39d18b8f53f7ce5" + integrity sha512-v4hIduIe/wzyibuL/RPM/ErYrt8XpB7fxyQqtV+0JsMpFa8E81QYyvMCS9EJj9m4YdkrQnZgA+vXQlOkhWvmdQ== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/checkbox" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/icon-button" "15.0.0-canary.b994146f6.0" + "@material/linear-progress" "15.0.0-canary.b994146f6.0" + "@material/list" "15.0.0-canary.b994146f6.0" + "@material/menu" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/select" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/density@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/density/-/density-15.0.0-canary.b994146f6.0.tgz#d29f7f1ad113b89acc3df10a4f05693faa8f12a4" + integrity sha512-m8l0vuoWSoAPItBpWp5eZDvitUcB2JWoO8V486hLgdveVcKgXG09xWM43ScH+PLXAWjzr5olDEuJ2tvfkN3SpQ== + dependencies: + tslib "^2.1.0" + +"@material/dialog@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-15.0.0-canary.b994146f6.0.tgz#41d02b3826fa36e17f4a8f06547fd58975e96120" + integrity sha512-JucU92yh8cfZQpyRBunHr6uohacePLYmhcPaGpkAGQ1b+zCznEsNs55tjhaVQNoj91XA9rrBqtL6Otg+fxFJtQ== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/button" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/icon-button" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/dom@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/dom/-/dom-15.0.0-canary.b994146f6.0.tgz#c5ef0fcb10f97ac4b8f18ec938f58ab4b563261a" + integrity sha512-DiUsTezrCi4iytjIn7xXoXZSNFvuTrVVZgc7cR9cW8yu2Hpz8bPf87PacVn4IP9OsNwy/dCDMk1Kcq/DMh7gXQ== + dependencies: + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/drawer@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-15.0.0-canary.b994146f6.0.tgz#0a33752e418e9e9e2b3169aaf08638bb58279c66" + integrity sha512-Kbuf32V0eX69amvCVbAjNSabNDerZWyG8ip466EfQHRh0OUZwvsbhLp9FZOB7AyR+/bQiHf3mVLcombOdmdkcQ== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/list" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/elevation@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-15.0.0-canary.b994146f6.0.tgz#85fc024f7503a882bd06e35f9c1a5c8f1e723319" + integrity sha512-l2YDNgBajSI6oA2l6gaeYCTGHRao657syqQ/tv95/Hkcee9900A4RrsxCwSxOqqAs5pZZDEJ33kFJjj27nqZDw== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/fab@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/fab/-/fab-15.0.0-canary.b994146f6.0.tgz#620a8da7223d6df314f0423b38e42e3697eae924" + integrity sha512-ExyDVkNWINpns41Ahj4u8I/OhiVkqI0nmcqjFRtgTJMmKEd4NhlvqIxE7gakAlyS68riJu5UleqTSTVmt8mv2Q== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/feature-targeting@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-15.0.0-canary.b994146f6.0.tgz#53e41308fc489908fa39ab5a6780aeaf6ffe93bf" + integrity sha512-HR/FjSQmza98B1DF80MRjODyfOI9r7wXkPSts/cLQsYkpwZ5uJmxhvQKjDCeYVpMV0lQuvuvVOQo7uD44TdWEg== + dependencies: + tslib "^2.1.0" + +"@material/floating-label@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-15.0.0-canary.b994146f6.0.tgz#a59712131c7c1c93c157b69c27a29b82af51549e" + integrity sha512-g64talBNWCS0FUfLWal0uB637gUciSIqYxFzSW//LglTtbZLGK2J4+9gAEswQGnKeO4ux08EN2n1ZcMDYQ58ow== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/focus-ring@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/focus-ring/-/focus-ring-15.0.0-canary.b994146f6.0.tgz#fa86a669ace6dee3c17bb810e59cf7909651b6ef" + integrity sha512-87qEMuXsCvlQfTiimnzJUZoebnIXWcMtRZevNLymN9Y0t9jGckQxZPmrI0llRkpyiR/Ewhec5SI/JGrFlYHnsA== + dependencies: + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + +"@material/form-field@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-15.0.0-canary.b994146f6.0.tgz#a3726178926c39da47140e858f53724f5e73b668" + integrity sha512-Tg1SQQaopvXMyDEYxGTWnhCWQmNcWVIoKMLmle9P/gi2p8ulcj0iOCPYf+3ECqUBVozOmTPKlYOOiRwtKStAeA== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/icon-button@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-15.0.0-canary.b994146f6.0.tgz#da5f7dae70ee00852aa328e6aadb237c79d10e38" + integrity sha512-X6DvOv4jpymHUjI7ZAbO946nDgGYKDwPZfkRzBE84gv2XEr2qfMuABhojxkYubRbt03oauBdcJVVMFCXkVhArQ== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/image-list@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-15.0.0-canary.b994146f6.0.tgz#a5abaeeed9f152fed2172a7ee45f70baa8704521" + integrity sha512-kf903XFF1P+V5ZPXCt+7R6c55g4UyQE1ZHkTViCIJfd52gU40bHODMhTQy/ywBkwDeJfNk8uf1V1IM24WQYpxA== + dependencies: + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/layout-grid@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-15.0.0-canary.b994146f6.0.tgz#b805c1c7510d0cae012c3b3d9826c3b90cc86d2b" + integrity sha512-OALBSGue8g1/mEwLYYi2d950dJFpNYKW87jPS9/KM65JKMyxoU7tU2d4An1BuyqK0r9sopGq6Pn/zhill0iLaw== + dependencies: + tslib "^2.1.0" + +"@material/line-ripple@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-15.0.0-canary.b994146f6.0.tgz#e0c9b1601352d690a5cf54043c23c95bf6f49059" + integrity sha512-evjZxCu4iodiKtW8N0xjY8ACRXm3sY+4rAmq3vV5BmHWAJ3BobjbFYslDMZQ+4mu3HmwMatbJehKxHegahitNg== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/linear-progress@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-15.0.0-canary.b994146f6.0.tgz#493da1a7e93e830cc26a95273a4bfe4f5f0dc617" + integrity sha512-jlXh+tIj+/o0Ks7fHdC/24fH6IXCAl2vF52U6NwT39ESrlwmlLhp3gtag5GSBHN5E7Z09nK871Yo1G/b1F+COg== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/progress-indicator" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/list@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/list/-/list-15.0.0-canary.b994146f6.0.tgz#dab708bd735bd72d3ba1379dc0a42989acc4caf7" + integrity sha512-kY/i6VvFBb/W3VvCPvWRMzWvu7mvNFJ+R8ijfawDoAXiv4fj42GO4iFyTcFXaUevEPKp791pN/09BMJQ6jYEvA== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/menu-surface@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-15.0.0-canary.b994146f6.0.tgz#9537b6bf8b8499311d82cb39b1367f03ab7b73a2" + integrity sha512-StmM3lrRn1iMEZfq532jpMNppqyBBy68FbPurKEsHuP/3q+CscfnwjrS9ym+JcHqXKMHnQXbL/49ymffRGX2AQ== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/menu@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/menu/-/menu-15.0.0-canary.b994146f6.0.tgz#f5ac72749b33b67dc413fa02fa1f6c6ae056327f" + integrity sha512-y6smNmLJ+U0DoXWbyqzW+VW/uWDuklhdGHc5MbZrTOhsKkhvoTVNMSOa+NFPU4gTwrplvUjaUvnIsQ0wygwD3g== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/list" "15.0.0-canary.b994146f6.0" + "@material/menu-surface" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/notched-outline@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-15.0.0-canary.b994146f6.0.tgz#5a405a7b12417f749a0150851db6cec3d446b4b6" + integrity sha512-UZxU8jXM2t/bk/CiO0K+TSPspuJRZIyrYlIS0gd+qq/u8Gi2DpALBlLAh9Jeu46IUg4YGlPsNWYfe8p3QAVyoA== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/floating-label" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/progress-indicator@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/progress-indicator/-/progress-indicator-15.0.0-canary.b994146f6.0.tgz#bf9005fd2e4c1b0faac21eef138a4c5c4745b681" + integrity sha512-VT+mOQhohaM+pBX1rknbVOI6JCGKg9NiOHBoYljIvnexNeILE+mW9g6mtQ0ZCJPz0oMmiSAMLcuxMIcBXx84Xw== + dependencies: + tslib "^2.1.0" + +"@material/radio@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/radio/-/radio-15.0.0-canary.b994146f6.0.tgz#aca0f63b672ddfc8b5162fa27561e7b7a84beb2d" + integrity sha512-U/RR2lVNWwEO2+kJtGz9XzvnOF0gAZn1krMY0z/eU9Wnl0OgPZbqQrxXMoVNv1pzKYSEwZQEGado/rv8qp7piA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/ripple@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-15.0.0-canary.b994146f6.0.tgz#6c86977b401ecf9222e134717cc240317eb5bfbd" + integrity sha512-WzIbc8wYTzMOczqGXVCBPdNcv/73Ef8FwcQYsscGMaqCzgVsdpoqilTfsx7Ryyz6dQbyfmJqp7s+YpPujcezOA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/rtl@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-15.0.0-canary.b994146f6.0.tgz#091de7871060edec6c743e14643fcf033014b673" + integrity sha512-H/W6BVn4Ygfkrf/FgSrNhbu1uY7PST2wlsjEYQt06EfAM0CDHEwSL1MwV4FmpQA/r40Q0PqoLN6moDrtCe5S8g== + dependencies: + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/segmented-button@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/segmented-button/-/segmented-button-15.0.0-canary.b994146f6.0.tgz#fb4c18f2aef530d74b6195bd9560407af20bc416" + integrity sha512-jd+f4BTnU0tghxBpAM/XdVmruDXSoQ88TYSFWbrhulS+/c/ooCZURWvVC4mHNej+QR/fODkx4adbqkBiwwCtMw== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/touch-target" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/select@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/select/-/select-15.0.0-canary.b994146f6.0.tgz#fc853a11383c327524ab9645fef80d6fbe8419f4" + integrity sha512-5thEQS+B17JSm3I8D+mqQe2G3ArVnXJALTEEE9FmMUKwKYkrsLplm3FYuEXERZGJnYeTRdkdmhYY/YeocfZoyA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/floating-label" "15.0.0-canary.b994146f6.0" + "@material/line-ripple" "15.0.0-canary.b994146f6.0" + "@material/list" "15.0.0-canary.b994146f6.0" + "@material/menu" "15.0.0-canary.b994146f6.0" + "@material/menu-surface" "15.0.0-canary.b994146f6.0" + "@material/notched-outline" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/shape@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/shape/-/shape-15.0.0-canary.b994146f6.0.tgz#ad1ea5c82bff40b2e76a13ec107010e7d568c862" + integrity sha512-sINM3gr3aLgdvqZVfqfXV5EB77owLLJjy+2NqchJ8ZPqucCJ+F/BsCBfLA2Wu3O4Sc9IpAEn/o1hzYm/CWAFAw== + dependencies: + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/slider@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/slider/-/slider-15.0.0-canary.b994146f6.0.tgz#2bbe6539a9d6aac602f093dadf62ef6f8e8afc7c" + integrity sha512-dyT72+Kp//AEajJxDUVoMoizUjf2uggVMGXOaQ7FhpGHuf7LC3EyEjrrJ15efFzYgTjdJUU1YQkCwGmdt6CQsA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/snackbar@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-15.0.0-canary.b994146f6.0.tgz#ab40dc533f4e4a0aee9847a4bb4232eecd6e1308" + integrity sha512-fEhPASJossScNpcrNYrrH8uU+rUf6+kw7/ZMrpUzzz1lVXliL28jTNEmU1nFpcDI4M2GXH+Z64f7vl2hiMDG8g== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/button" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/icon-button" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/switch@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/switch/-/switch-15.0.0-canary.b994146f6.0.tgz#e373ff8523736c3c3f1cdd25cd3e8756e8c25b54" + integrity sha512-czCXTUa30ILIf1J3exiuSVIRcodGATHexd3eWDq4sfHo4iMh4rBMaIxcqkmnb2iwE/mMTNyVfoauijx2QiNKrA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + safevalues "^0.3.4" + tslib "^2.1.0" + +"@material/tab-bar@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-15.0.0-canary.b994146f6.0.tgz#5c6d0c493b154632f433ac519ca56a75b65ef469" + integrity sha512-F9NegACnFEWMu1pAAypV4Jd7qROeffkvEgVO28Xxk/CvzZxFz8kAjYJZ+rI6RUhPX3BhXzwsz/AlLwsJMT2tnA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/tab" "15.0.0-canary.b994146f6.0" + "@material/tab-indicator" "15.0.0-canary.b994146f6.0" + "@material/tab-scroller" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/tab-indicator@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-15.0.0-canary.b994146f6.0.tgz#927843ab41cf6f42e878612e90c93ae3278851ca" + integrity sha512-8IH/DmwlZhQlw/2Y3aKrEvjEhZB+qbKUiyaij3BkTAexvyFeDBh5cLNjRpYkUJSGeSPhS6yu4SYzMHPmQEwQmA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/tab-scroller@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-15.0.0-canary.b994146f6.0.tgz#979e31b602b062c0995bd888aef8dfcb239f6c5e" + integrity sha512-1MeWkr62OICfTv8oqhIZe6jFo0dKeMlUfB+/WcgnpoeMBszCOSlx5tQ4pedxUkuR3I+Z7rsTfSN0LavgF8bATA== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/tab" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/tab@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/tab/-/tab-15.0.0-canary.b994146f6.0.tgz#f03b6706954fb0033817b451731bfadf9946f527" + integrity sha512-ygswooiNdBNNDnQdbPX0nzDQu7oQlHo8vWZ0/xL4IPVEXabY5zCzsEbGNZw2u/syo56c/NHPyMsUmXDGRSXOvQ== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/focus-ring" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/tab-indicator" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/textfield@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-15.0.0-canary.b994146f6.0.tgz#b1188830a0d9884bcfa69f6db816132b4cca5735" + integrity sha512-Kxb3DoJ5o8u3Y1gRMHKmWrDl1TirVxuf/UFrxPFiCE3J1SqiE2VQpakiD1emZwp+LSKtbRsQ/iILYLB/h7Wuvw== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/density" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/floating-label" "15.0.0-canary.b994146f6.0" + "@material/line-ripple" "15.0.0-canary.b994146f6.0" + "@material/notched-outline" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/theme@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/theme/-/theme-15.0.0-canary.b994146f6.0.tgz#85ac9a1336c8849f0c9ca1d5218f969ae58f8738" + integrity sha512-5tsZ92dAeUcZ9g9CrIkqX/GYc0M5DIfsydtI1PAidaBzr1Uokuh4rTZVQZBv7gyglF0yDua59lkb0I6wI9vxXg== + dependencies: + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/tokens@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/tokens/-/tokens-15.0.0-canary.b994146f6.0.tgz#55ad3d7687d941b3f7d1d736dcfa91df9e97c590" + integrity sha512-jFqU7PtvGkrP8b8i2soCrYQInTrnZ1/rIPDi+Xm3sa/qSghCNwFrdJEqwcwtv1fPlJIOtzkIuVRYRmAP9rXQIQ== + dependencies: + "@material/elevation" "15.0.0-canary.b994146f6.0" + +"@material/tooltip@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/tooltip/-/tooltip-15.0.0-canary.b994146f6.0.tgz#1af251aba50669ee7e1c3f5d57961ee0a1138d47" + integrity sha512-bVzydXGn3fauHJ8pkh32DsdyRJXleeFQ4t7jZ/rcRik+n4G1BvYiblfuu3Z/OCC0m3TJDyMdJhd+sLqRDqLUUg== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/button" "15.0.0-canary.b994146f6.0" + "@material/dom" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/tokens" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + safevalues "^0.3.4" + tslib "^2.1.0" + +"@material/top-app-bar@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-15.0.0-canary.b994146f6.0.tgz#2fe6ef4cf1f19c6bca41eaed583e78032a49d86e" + integrity sha512-VHq0wX3OJE1TKvjO8Qtlu+rv5EGoqAhNLBcEjpUUGoqHH/gpd356FEuIqJId4pUh5jaWf8T4ZU9xVbQGMtntzw== + dependencies: + "@material/animation" "15.0.0-canary.b994146f6.0" + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/elevation" "15.0.0-canary.b994146f6.0" + "@material/ripple" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/shape" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + "@material/typography" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/touch-target@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/touch-target/-/touch-target-15.0.0-canary.b994146f6.0.tgz#b00f2507a36c7341d2de7c590664894ce3a77815" + integrity sha512-X26Y9OWvIqYOHo+sC2VMvOoeQWlUR3/yb7uPdfq92Y44zlQ4Vexgq7nEUblEiXQ8Fj+d0T9rIhRh1y9PP3Z2dw== + dependencies: + "@material/base" "15.0.0-canary.b994146f6.0" + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/rtl" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@material/typography@15.0.0-canary.b994146f6.0": + version "15.0.0-canary.b994146f6.0" + resolved "https://registry.yarnpkg.com/@material/typography/-/typography-15.0.0-canary.b994146f6.0.tgz#d3c4cfb6c9249af34ce8e334f2824ded156accc9" + integrity sha512-sWU5W30WWqdw5P6bsRx9AbvMNcz/QvQg56Syr06V6nfgSztpeuo7TfPk2J+N0ArRALo1mUrkAPk66iWYQ2p/QA== + dependencies: + "@material/feature-targeting" "15.0.0-canary.b994146f6.0" + "@material/theme" "15.0.0-canary.b994146f6.0" + tslib "^2.1.0" + +"@ngtools/webpack@16.1.4": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-16.1.4.tgz#2e29bdf590c8b5505ffd744f12075b14ed972fc8" + integrity sha512-+8bfavDH8eWxjlJFYr6bkjcRHhy95j+f8oNn7/sGLNu4L96nuE2AZ011XIu2dJahCnNiBvwc1EpkKa92t9rkaA== + +"@ngx-translate/core@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-14.0.0.tgz#af421d0e1a28376843f0fed375cd2fae7630a5ff" + integrity sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w== + dependencies: + tslib "^2.3.0" + +"@nicolo-ribaudo/semver-v6@^6.3.3": + version "6.3.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29" + integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@npmcli/fs@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" + integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ== + dependencies: + "@gar/promisify" "^1.1.3" + semver "^7.3.5" + +"@npmcli/fs@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.0.tgz#233d43a25a91d68c3a863ba0da6a3f00924a173e" + integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== + dependencies: + semver "^7.3.5" + +"@npmcli/git@^4.0.0": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-4.0.4.tgz#cdf74f21b1d440c0756fb28159d935129d9daa33" + integrity sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg== + dependencies: + "@npmcli/promise-spawn" "^6.0.0" + lru-cache "^7.4.4" + npm-pick-manifest "^8.0.0" + proc-log "^3.0.0" + promise-inflight "^1.0.1" + promise-retry "^2.0.1" + semver "^7.3.5" + which "^3.0.0" + +"@npmcli/installed-package-contents@^2.0.1": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33" + integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ== + dependencies: + npm-bundled "^3.0.0" + npm-normalize-package-bin "^3.0.0" + +"@npmcli/move-file@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4" + integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@npmcli/node-gyp@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a" + integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA== + +"@npmcli/promise-spawn@^6.0.0", "@npmcli/promise-spawn@^6.0.1": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz#c8bc4fa2bd0f01cb979d8798ba038f314cfa70f2" + integrity sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg== + dependencies: + which "^3.0.0" + +"@npmcli/run-script@^6.0.0": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.2.tgz#a25452d45ee7f7fb8c16dfaf9624423c0c0eb885" + integrity sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA== + dependencies: + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/promise-spawn" "^6.0.0" + node-gyp "^9.0.0" + read-package-json-fast "^3.0.0" + which "^3.0.0" + +"@nrwl/devkit@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.0.2.tgz#31fdd399868f85a329988b59c20bb3a19925b4f5" + integrity sha512-SAEcImeQHdSTauO05FUn2vVl9/y5Kx1LNCZ4YE+SdY5/QRq18fuo/DCWmjOGG9M8r06vYGsAgMzkiB4soimcyA== + dependencies: + "@nx/devkit" "16.0.2" + +"@nrwl/tao@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-16.0.2.tgz#ad0bef6a25d3609f781eddb4e89364ff6a5aa3e2" + integrity sha512-wimEe4OTpI7/nDK67RnpZpEXCU+fzA0sDgpIhMgbpPd0vPmKgaZv4nbs8zrm0goFlacmmnLaGRhhGYMOxE+1Lg== + dependencies: + nx "16.0.2" + +"@nx/devkit@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-16.0.2.tgz#6109d6f5e9bdef612fbddecd81b2dad20f91a626" + integrity sha512-BY1Bj0BbAl6XJL0O+QGTWPs/3WMJTEQ+Y4Lfoq4dZM7RllE6rAylr54NA2wa4lsgordZhq1+0g5PVhKKvSVRRw== + dependencies: + "@nrwl/devkit" "16.0.2" + ejs "^3.1.7" + ignore "^5.0.4" + semver "7.3.4" + tmp "~0.2.1" + tslib "^2.3.0" + +"@nx/nx-darwin-arm64@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.0.2.tgz#6258cb524655d6db4d549c748398c96ac3b4bbbd" + integrity sha512-nAT8WJ/qKGEvUcoFLHHye1dbwCd7b8CTZJlDF+ZkyCD/UZRHt4eJxy8gvKmxgkZTFb2+PPMQt4UORCUGpZzuoA== + +"@nx/nx-darwin-x64@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.0.2.tgz#7e25eb1db6aa3ea835454d0c7f8edb9d16367d79" + integrity sha512-r0rfOrZaOyrwFR5a0UT05xkYRumfkP65cRSZM1TjCA027AG9llYtkLT1hlz8uMKt+P12zrWVzXSqGLDi022ZZg== + +"@nx/nx-linux-arm-gnueabihf@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.0.2.tgz#635b9cdfecb647efbcf9194dfb8a6c40eed322dc" + integrity sha512-TfDQaGvCIDjn9sPg5U1Fr2rsSul/4PIQB59qrLBJRPiCWgpzwO71Il1qwSX68En+JH3lwXr+g5EjcDIEQ8fGYA== + +"@nx/nx-linux-arm64-gnu@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.0.2.tgz#8a5b208fd754bc4525b39455731d84849c579ede" + integrity sha512-MICaUp7uz8WVQFXWPrmQaX1o4bdL7f3C7b3MDDf6+Zau6RcyQuw97UEKaYi9OqrV3w8yuPplqoLosFblAgb8uw== + +"@nx/nx-linux-arm64-musl@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.0.2.tgz#03e24880f548a99420464eadb332a58ebd05862d" + integrity sha512-wcBURG+6A2srm+6ujj8SShjwmYWs0eHI5D8vgZr8Bni+lXbKP/IosE9JGXKtRoh27/owyR8PGHhDVzjv46tlFg== + +"@nx/nx-linux-x64-gnu@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.0.2.tgz#9105f334c93fc4552653f82e4d2969c8d84c43bd" + integrity sha512-Xyml2gFdVDHUj2g67DKz2aD78x1BciN1ZaaBTCxXL4MHfwR78SZa7mtRtE+1kj5OgVIwupZP50jq7C8GuSn3Hw== + +"@nx/nx-linux-x64-musl@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.0.2.tgz#ffd9ee630ebb45eda53925d50ec50d058d129dcb" + integrity sha512-j3xdN8I5DlTgW5N5eCquyBZswrrYf6EazUCvnEpeejygwh3N6XN7DlD68Bs0CB4Zmd0tWLfTjNVAtUJSP6g2mA== + +"@nx/nx-win32-arm64-msvc@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.0.2.tgz#2f65e5e8ceb1818ad63056fdf9e8e8bd097c1e43" + integrity sha512-R2pzoW3SUFBbe9C1vifJnXuysPl6kmutQHN2yQ9lwJptzPvMxfDU1FuXmKCGRUGmEwFxk/XPhwDL/ZcbABTrzw== + +"@nx/nx-win32-x64-msvc@16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.0.2.tgz#eb29298e39f3688f5a73480ba34cf1b2463a5e6f" + integrity sha512-r4H/SsqfpIJa8QLSpnscgkMnLsnkRYXj8TcILDrf+nJazfEdJZLUvVhN9O85OB7pskv86NuGfnJmJHHXy6QVQg== + +"@parcel/watcher@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.4.tgz#f300fef4cc38008ff4b8c29d92588eced3ce014b" + integrity sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg== + dependencies: + node-addon-api "^3.2.1" + node-gyp-build "^4.3.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@schematics/angular@16.1.4": + version "16.1.4" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-16.1.4.tgz#e99a8b7e1b1b9db107727d0e26a05dc190eefeea" + integrity sha512-XfoeL+aBVIR/DzgVKGVhHW/TGQnqWvngyJVuCwXEVWzNfjxHYFkchXa78OItpAvTEr6/Y0Me9FQVAGVA4mMUyg== + dependencies: + "@angular-devkit/core" "16.1.4" + "@angular-devkit/schematics" "16.1.4" + jsonc-parser "3.2.0" + +"@sigstore/protobuf-specs@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz#957cb64ea2f5ce527cc9cf02a096baeb0d2b99b4" + integrity sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ== + +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@tufjs/canonical-json@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz#eade9fd1f537993bc1f0949f3aea276ecc4fab31" + integrity sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ== + +"@tufjs/models@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tufjs/models/-/models-1.0.4.tgz#5a689630f6b9dbda338d4b208019336562f176ef" + integrity sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A== + dependencies: + "@tufjs/canonical-json" "1.0.0" + minimatch "^9.0.0" + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/codemirror@^5.60.5": + version "5.60.7" + resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.7.tgz#efbb78e5e79f90c6762c2127c02096648e600808" + integrity sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA== + dependencies: + "@types/tern" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#9fd20b3974bdc2bcd4ac6567e2e0f6885cb2cf41" + integrity sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.13" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" + integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.37.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.37.0.tgz#29cebc6c2a3ac7fea7113207bf5a828fdf4d7ef1" + integrity sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": + version "4.17.35" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/file-saver@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.5.tgz#9ee342a5d1314bb0928375424a2f162f97c310c7" + integrity sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ== + +"@types/google-protobuf@^3.15.3": + version "3.15.6" + resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.6.tgz#674a69493ef2c849b95eafe69167ea59079eb504" + integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw== + +"@types/http-proxy@^1.17.8": + version "1.17.11" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.11.tgz#0ca21949a5588d55ac2b659b69035c84bd5da293" + integrity sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA== + dependencies: + "@types/node" "*" + +"@types/jasmine@*": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-4.3.1.tgz#2d8ab5601c2fe7d9673dcb157e03f128ab5c5fff" + integrity sha512-Vu8l+UGcshYmV1VWwULgnV/2RDbBaO6i2Ptx7nd//oJPIZGhoI1YLST4VKagD2Pq/Bc2/7zvtvhM7F3p4SN7kQ== + +"@types/jasmine@~4.3.3": + version "4.3.5" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-4.3.5.tgz#05c6b401c041b8a4f3303c3a58c9580aac2b898c" + integrity sha512-9YHUdvuNDDRJYXZwHqSsO72Ok0vmqoJbNn73ttyITQp/VA60SarnZ+MPLD37rJAhVoKp+9BWOvJP5tHIRfZylQ== + +"@types/jasminewd2@~2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.10.tgz#ae31c237aa6421bde30f1058b1d20f4577e54443" + integrity sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g== + dependencies: + "@types/jasmine" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/jsonwebtoken@^9.0.1": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#9eeb56c76dd555039be2a3972218de5bd3b8d83e" + integrity sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q== + dependencies: + "@types/node" "*" + +"@types/long@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0": + version "20.1.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.5.tgz#e94b604c67fc408f215fcbf3bd84d4743bf7f710" + integrity sha512-IvGD1CD/nego63ySR7vrAKEX3AJTcmrAN2kn+/sDNLi1Ff5kBzDeEdqWDplK+0HAEoLYej137Sk0cUU8OLOlMg== + +"@types/node@^18.15.11": + version "18.16.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.10.tgz#9b16d918f4f6fec6cae4af34283a91d555b81519" + integrity sha512-sMo3EngB6QkMBlB9rBe1lFdKSLqljyWPPWv6/FzSxh/IDlyVWSzE9RiF4eAuerQHybrWdqBgAGb03PM89qOasA== + +"@types/opentype.js@^1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@types/opentype.js/-/opentype.js-1.3.4.tgz#d9ef2e6ed3ba9d2b6822e38febb1834fb037641b" + integrity sha512-6fbXi67I07ugNM+FExwJnfuui2hD7hraD6nqjr3UnqsbBpxSkrtmO6tBubPdNAjqRT9TVkquVkNS9IkgTtq6/w== + +"@types/q@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" + integrity sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug== + +"@types/qrcode@1.5.0", "@types/qrcode@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.5.0.tgz#6a98fe9a9a7b2a9a3167b6dde17eff999eabe40b" + integrity sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA== + dependencies: + "@types/node" "*" + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/selenium-webdriver@^3.0.0": + version "3.0.21" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.21.tgz#af7a272e7f92a89cd432005dd1cb80956ebe4d9b" + integrity sha512-DRHyGEr25ra2C4+eU7eiCSto2j9eUa9pR4z5uiLRBXWFlmfMCAeXwecZnAhuB3eOOCA8OkwcNlb6QUkVZFlKTA== + +"@types/semver@^7.3.12": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/send@*": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.1" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" + integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== + dependencies: + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/tern@*": + version "0.23.4" + resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" + integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== + dependencies: + "@types/estree" "*" + +"@types/uuid@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6" + integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA== + +"@types/ws@^8.5.1": + version "8.5.4" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" + integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@^5.59.11": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz#a1a5290cf33863b4db3fb79350b3c5275a7b1223" + integrity sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.61.0" + "@typescript-eslint/type-utils" "5.61.0" + "@typescript-eslint/utils" "5.61.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.59.5": + version "5.59.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.6.tgz#bd36f71f5a529f828e20b627078d3ed6738dbb40" + integrity sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA== + dependencies: + "@typescript-eslint/scope-manager" "5.59.6" + "@typescript-eslint/types" "5.59.6" + "@typescript-eslint/typescript-estree" "5.59.6" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz#f699fe936ee4e2c996d14f0fdd3a7da5ba7b9a4c" + integrity sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA== + dependencies: + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/visitor-keys" "5.59.2" + +"@typescript-eslint/scope-manager@5.59.6": + version "5.59.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz#d43a3687aa4433868527cfe797eb267c6be35f19" + integrity sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ== + dependencies: + "@typescript-eslint/types" "5.59.6" + "@typescript-eslint/visitor-keys" "5.59.6" + +"@typescript-eslint/scope-manager@5.61.0": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.61.0.tgz#b670006d069c9abe6415c41f754b1b5d949ef2b2" + integrity sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw== + dependencies: + "@typescript-eslint/types" "5.61.0" + "@typescript-eslint/visitor-keys" "5.61.0" + +"@typescript-eslint/type-utils@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf" + integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/utils" "5.59.2" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/type-utils@5.61.0": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.61.0.tgz#e90799eb2045c4435ea8378cb31cd8a9fddca47a" + integrity sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg== + dependencies: + "@typescript-eslint/typescript-estree" "5.61.0" + "@typescript-eslint/utils" "5.61.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655" + integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w== + +"@typescript-eslint/types@5.59.6": + version "5.59.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.6.tgz#5a6557a772af044afe890d77c6a07e8c23c2460b" + integrity sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA== + +"@typescript-eslint/types@5.61.0": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.61.0.tgz#e99ff11b5792d791554abab0f0370936d8ca50c0" + integrity sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ== + +"@typescript-eslint/typescript-estree@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936" + integrity sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q== + dependencies: + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/visitor-keys" "5.59.2" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@5.59.6": + version "5.59.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz#2fb80522687bd3825504925ea7e1b8de7bb6251b" + integrity sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA== + dependencies: + "@typescript-eslint/types" "5.59.6" + "@typescript-eslint/visitor-keys" "5.59.6" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@5.61.0": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.61.0.tgz#4c7caca84ce95bb41aa585d46a764bcc050b92f3" + integrity sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw== + dependencies: + "@typescript-eslint/types" "5.61.0" + "@typescript-eslint/visitor-keys" "5.61.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4" + integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.59.2" + "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/typescript-estree" "5.59.2" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/utils@5.61.0": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.61.0.tgz#5064838a53e91c754fffbddd306adcca3fe0af36" + integrity sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.61.0" + "@typescript-eslint/types" "5.61.0" + "@typescript-eslint/typescript-estree" "5.61.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.59.2": + version "5.59.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750" + integrity sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig== + dependencies: + "@typescript-eslint/types" "5.59.2" + eslint-visitor-keys "^3.3.0" + +"@typescript-eslint/visitor-keys@5.59.6": + version "5.59.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz#673fccabf28943847d0c8e9e8d008e3ada7be6bb" + integrity sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q== + dependencies: + "@typescript-eslint/types" "5.59.6" + eslint-visitor-keys "^3.3.0" + +"@typescript-eslint/visitor-keys@5.61.0": + version "5.61.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.61.0.tgz#c79414fa42158fd23bd2bb70952dc5cdbb298140" + integrity sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg== + dependencies: + "@typescript-eslint/types" "5.61.0" + eslint-visitor-keys "^3.3.0" + +"@vitejs/plugin-basic-ssl@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz#48c46eab21e0730921986ce742563ae83fe7fe34" + integrity sha512-pcub+YbFtFhaGRTo1832FQHQSHvMrlb43974e2eS8EKleR3p1cDdkJFPci1UhwkEf1J9Bz+wKBSzqpKp7nNj2A== + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +"@yarnpkg/lockfile@1.1.0", "@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +"@yarnpkg/parsers@^3.0.0-rc.18": + version "3.0.0-rc.43" + resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.43.tgz#2bf720ec6444e3f002f40dce734c262e9f3d888a" + integrity sha512-AhFF3mIDfA+jEwQv2WMHmiYhOvmdbh2qhUkDVQfiqzQtUwS4BgoWwom5NpSPg4Ix5vOul+w1690Bt21CkVLpgg== + dependencies: + js-yaml "^3.10.0" + tslib "^2.4.0" + +"@zkochan/js-yaml@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz#975f0b306e705e28b8068a07737fa46d3fc04826" + integrity sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg== + dependencies: + argparse "^2.0.1" + +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +abbrev@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +acorn@^8.8.2: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +adjust-sourcemap-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" + integrity sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A== + dependencies: + loader-utils "^2.0.0" + regex-parser "^2.2.11" + +adm-zip@^0.5.2: + version "0.5.10" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.10.tgz#4a51d5ab544b1f5ce51e1b9043139b639afff45b" + integrity sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ== + +agent-base@6, agent-base@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" + integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== + dependencies: + debug "^4.1.0" + depd "^2.0.0" + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-formats@2.1.1, ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@8.12.0, ajv@^8.0.0, ajv@^8.9.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +angular-oauth2-oidc@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/angular-oauth2-oidc/-/angular-oauth2-oidc-15.0.1.tgz#ba3bcb88e565be7ea4c635a48524963c677be2fe" + integrity sha512-5gpqO9QL+qFqMItYFHe8F6H5nOIEaowcNUc9iTDs3P1bfVYnoKoVAaijob53PuPTF4YwzdfwKWZi4Mq6P7GENQ== + dependencies: + tslib "^2.0.0" + +angularx-qrcode@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/angularx-qrcode/-/angularx-qrcode-16.0.0.tgz#c637924b8d8f9cc344216caa80adf3810ccd5e5b" + integrity sha512-j6IndIU3m4zfqSPKraJPFgigdHa+pM3kapRPBnKSwgKNSpljPQu3XNiRUCmQmfGfnh39ShDVca/k091WTjngAA== + dependencies: + "@types/qrcode" "1.5.0" + qrcode "1.5.1" + tslib "^2.3.0" + +ansi-colors@4.1.3, ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +app-root-path@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86" + integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== + +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw== + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== + dependencies: + array-uniq "^1.0.1" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +ast-types-flow@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== + +async@^3.2.3: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +autoprefixer@10.4.14: + version "10.4.14" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" + integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== + dependencies: + browserslist "^4.21.5" + caniuse-lite "^1.0.30001464" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== + +axios@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axobject-query@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" + integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww== + dependencies: + ast-types-flow "0.0.7" + +axobject-query@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" + integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== + dependencies: + deep-equal "^2.0.5" + +babel-loader@9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-9.1.2.tgz#a16a080de52d08854ee14570469905a5fc00d39c" + integrity sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA== + dependencies: + find-cache-dir "^3.3.2" + schema-utils "^4.0.0" + +babel-plugin-istanbul@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-polyfill-corejs2@^0.4.3: + version "0.4.4" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz#9f9a0e1cd9d645cc246a5e094db5c3aa913ccd2b" + integrity sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.4.1" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + +babel-plugin-polyfill-corejs3@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz#d406c5738d298cd9c66f64a94cf8d5904ce4cc5e" + integrity sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.1" + core-js-compat "^3.31.0" + +babel-plugin-polyfill-regenerator@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz#ace7a5eced6dff7d5060c335c52064778216afd3" + integrity sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.1" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.2.0, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bl@^4.0.3, bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== + dependencies: + minimist "^1.2.0" + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +body-parser@^1.19.0: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour-service@^1.0.11: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" + integrity sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg== + dependencies: + array-flatten "^2.1.2" + dns-equal "^1.0.0" + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.14.5, browserslist@^4.21.3, browserslist@^4.21.5: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== + dependencies: + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" + +browserslist@^4.21.9: + version "4.21.9" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635" + integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== + dependencies: + caniuse-lite "^1.0.30001503" + electron-to-chromium "^1.4.431" + node-releases "^2.0.12" + update-browserslist-db "^1.0.11" + +browserstack@^1.5.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3" + integrity sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw== + dependencies: + https-proxy-agent "^2.2.1" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +builtins@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cacache@17.1.3: + version "17.1.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.3.tgz#c6ac23bec56516a7c0c52020fd48b4909d7c7044" + integrity sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^7.7.1" + minipass "^5.0.0" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + +cacache@^16.1.0: + version "16.1.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" + integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ== + dependencies: + "@npmcli/fs" "^2.1.0" + "@npmcli/move-file" "^2.0.0" + chownr "^2.0.0" + fs-minipass "^2.1.0" + glob "^8.0.1" + infer-owner "^1.0.4" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + mkdirp "^1.0.4" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^9.0.0" + tar "^6.1.11" + unique-filename "^2.0.0" + +cacache@^17.0.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.0.tgz#b7286ef941dafe55b461cdcdceda71cacc1eb98d" + integrity sha512-hXpFU+Z3AfVmNuiLve1qxWHMq0RSIt5gjCKAHi/M6DktwFwDdAXAtunl1i4WSKaaVcU9IsRvXFg42jTHigcC6Q== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^7.7.1" + minipass "^5.0.0" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: + version "1.0.30001487" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001487.tgz#d882d1a34d89c11aea53b8cdc791931bdab5fe1b" + integrity sha512-83564Z3yWGqXsh2vaH/mhXfEM0wX+NlBCm1jYHOb97TrTWJEmPTccZgeLTPBUUb0PNVo+oomb7wkimZBIERClA== + +caniuse-lite@^1.0.30001503: + version "1.0.30001513" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001513.tgz#382fe5fbfb0f7abbaf8c55ca3ac71a0307a752e9" + integrity sha512-pnjGJo7SOOjAGytZZ203Em95MRM8Cr6jhCXNF/FAXTpCTRTECnqQWLpiTRqrFtdYcth8hf4WECUpkezuYsMVww== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.1, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@3.1.0, cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +cli-spinners@^2.5.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db" + integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + +codelyzer@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-6.0.2.tgz#25d72eae641e8ff13ffd7d99b27c9c7ad5d7e135" + integrity sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g== + dependencies: + "@angular/compiler" "9.0.0" + "@angular/core" "9.0.0" + app-root-path "^3.0.0" + aria-query "^3.0.0" + axobject-query "2.0.2" + css-selector-tokenizer "^0.7.1" + cssauron "^1.4.0" + damerau-levenshtein "^1.0.4" + rxjs "^6.5.3" + semver-dsl "^1.0.1" + source-map "^0.5.7" + sprintf-js "^1.1.2" + tslib "^1.10.0" + zone.js "~0.10.3" + +codemirror@^5.65.8: + version "5.65.13" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.13.tgz#c098a6f409db8b5a7c5722788bd9fa3bb2367f2e" + integrity sha512-SVWEzKXmbHmTQQWaz03Shrh4nybG0wXx2MEu3FO4ezbPW8IbnZEd5iGHGEffSUaitKYa3i+pHpBsSvw8sPHtzg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +colorette@^2.0.10: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +colors@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.11.0, commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.5.1, convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +copy-anything@^2.0.1: + version "2.0.6" + resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480" + integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw== + dependencies: + is-what "^3.14.1" + +copy-webpack-plugin@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" + integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== + dependencies: + fast-glob "^3.2.11" + glob-parent "^6.0.1" + globby "^13.1.1" + normalize-path "^3.0.0" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" + +core-js-compat@^3.30.2, core-js-compat@^3.31.0: + version "3.31.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.31.1.tgz#5084ad1a46858df50ff89ace152441a63ba7aae0" + integrity sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA== + dependencies: + browserslist "^4.21.9" + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@^2.8.5, cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cosmiconfig@^8.1.3: + version "8.1.3" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689" + integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw== + dependencies: + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + +critters@0.0.19: + version "0.0.19" + resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.19.tgz#15e3a3a0ed77ae4b69c3b2fe29c8e7e87fc77d1b" + integrity sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw== + dependencies: + chalk "^4.1.0" + css-select "^5.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.2" + htmlparser2 "^8.0.2" + postcss "^8.4.23" + pretty-bytes "^5.3.0" + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-loader@6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" + integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.21" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.3" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.2.0" + semver "^7.3.8" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-selector-tokenizer@^0.7.1: + version "0.7.3" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" + integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== + dependencies: + cssesc "^3.0.0" + fastparse "^1.1.2" + +css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +cssauron@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" + integrity sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw== + dependencies: + through X.X.X + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== + +damerau-levenshtein@^1.0.4: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.1.0, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +deep-equal@^2.0.5: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.1.tgz#c72ab22f3a7d3503a4ca87dde976fe9978816739" + integrity sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.0" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.0" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +del@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + integrity sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ== + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +depd@2.0.0, depd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== + +diacritics@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/diacritics/-/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1" + integrity sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA== + +dijkstrajs@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23" + integrity sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.6.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" + integrity sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dotenv@~10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + +duplexer@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +ejs@^3.1.7: + version "3.1.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" + integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.4.284: + version "1.4.396" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.396.tgz#3d3664eb58d86376fbe2fece3705f68ca197205c" + integrity sha512-pqKTdqp/c5vsrc0xUPYXTDBo9ixZuGY8es4ZOjjd6HD6bFYbu5QA09VoW3fkY4LF1T0zYk86lN6bZnNlBuOpdQ== + +electron-to-chromium@^1.4.431: + version "1.4.453" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.453.tgz#0a81fdc1943db202e8724d9f61369a71f0dd51e8" + integrity sha512-BU8UtQz6CB3T7RIGhId4BjmjJVXQDujb0+amGL8jpcluFJr6lwspBOvkUbnttfpZCm4zFMHmjrX1QrdPWBBMjQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encoding@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +engine.io-parser@~5.0.3: + version "5.0.6" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.6.tgz#7811244af173e157295dec9b2718dfe42a64ef45" + integrity sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw== + +engine.io@~6.4.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.4.2.tgz#ffeaf68f69b1364b0286badddf15ff633476473f" + integrity sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.11.0" + +enhanced-resolve@^5.14.1: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enquirer@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== + +entities@^4.2.0, entities@^4.3.0, entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +errno@^0.1.1: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-module-lexer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527" + integrity sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg== + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +esbuild-wasm@0.17.19: + version "0.17.19" + resolved "https://registry.yarnpkg.com/esbuild-wasm/-/esbuild-wasm-0.17.19.tgz#c528495c5363c34a4671fa55404e2b0ba85566ba" + integrity sha512-X9UQEMJMZXwlGCfqcBmJ1jEa+KrLfd+gCBypO/TSzo5hZvbVwFqpxj1YCuX54ptTF75wxmrgorR4RL40AKtLVg== + +esbuild@0.17.19, esbuild@^0.17.5: + version "0.17.19" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955" + integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw== + optionalDependencies: + "@esbuild/android-arm" "0.17.19" + "@esbuild/android-arm64" "0.17.19" + "@esbuild/android-x64" "0.17.19" + "@esbuild/darwin-arm64" "0.17.19" + "@esbuild/darwin-x64" "0.17.19" + "@esbuild/freebsd-arm64" "0.17.19" + "@esbuild/freebsd-x64" "0.17.19" + "@esbuild/linux-arm" "0.17.19" + "@esbuild/linux-arm64" "0.17.19" + "@esbuild/linux-ia32" "0.17.19" + "@esbuild/linux-loong64" "0.17.19" + "@esbuild/linux-mips64el" "0.17.19" + "@esbuild/linux-ppc64" "0.17.19" + "@esbuild/linux-riscv64" "0.17.19" + "@esbuild/linux-s390x" "0.17.19" + "@esbuild/linux-x64" "0.17.19" + "@esbuild/netbsd-x64" "0.17.19" + "@esbuild/openbsd-x64" "0.17.19" + "@esbuild/sunos-x64" "0.17.19" + "@esbuild/win32-arm64" "0.17.19" + "@esbuild/win32-ia32" "0.17.19" + "@esbuild/win32-x64" "0.17.19" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.0.0, eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@^8.39.0: + version "8.40.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.40.0.tgz#a564cd0099f38542c4e9a2f630fa45bf33bc42a4" + integrity sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.3" + "@eslint/js" "8.40.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.5.2" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +espree@^9.5.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" + integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter-asyncresource@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz#734ff2e44bf448e627f7748f905d6bdd57bdb65b" + integrity sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +express@^4.17.3: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@3.2.12, fast-glob@^3.2.11, fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastparse@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" + integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +figures@3.2.0, figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-saver@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" + integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== + +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-cache-dir@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flag-icons@^6.6.6: + version "6.6.6" + resolved "https://registry.yarnpkg.com/flag-icons/-/flag-icons-6.6.6.tgz#9ddff81e1126778ca6a5a1e0e2cfac2e865f2cb7" + integrity sha512-4lHDKxldnQ7q617pf9Dx9nAetT+9zcMpUexbRrc9kjLw9KJgZ83zA5Dky3Vv7ZDzUjAiZ46x/cy5P0HnEnqA2A== + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.1.0, flatted@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0, follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^11.1.0: + version "11.1.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" + integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^2.0.0, fs-minipass@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-minipass@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.2.tgz#5b383858efa8c1eb8c33b39e994f7e8555b8b3a3" + integrity sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g== + dependencies: + minipass "^5.0.0" + +fs-monkey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1, glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^10.2.2: + version "10.2.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.4.tgz#f5bf7ddb080e3e9039b148a9e2aef3d5ebfc0a25" + integrity sha512-fDboBse/sl1oXSLhIp0FcCJgzW9KmhC/q8ULTKC82zc+DL3TL7FNb8qlt5qqXN53MsKEUSIcb+7DLmEygOE5Yw== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.0.3" + minimatch "^9.0.0" + minipass "^5.0.0 || ^6.0.0" + path-scurry "^1.7.0" + +glob@^7.0.3, glob@^7.0.6, glob@^7.1.3, glob@^7.1.4, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +globby@^13.1.1: + version "13.1.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.4.tgz#2f91c116066bcec152465ba36e5caa4a13c01317" + integrity sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g== + dependencies: + dir-glob "^3.0.1" + fast-glob "^3.2.11" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^4.0.0" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + integrity sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ== + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +google-proto-files@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/google-proto-files/-/google-proto-files-3.0.3.tgz#73e116854df2167c1dcb02eb878c10b882bf7f26" + integrity sha512-7JaU/smPA/FpNsCaXyVjitwiQyn5zYC/ETA+xag3ziovBojIWvzevyrbVqhxgnQdgMJ0p1RVSvpzQL6hkg6yGw== + dependencies: + protobufjs "^7.0.0" + walkdir "^0.4.0" + +google-protobuf@^3.21.2: + version "3.21.2" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4" + integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +grpc-web@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/grpc-web/-/grpc-web-1.4.2.tgz#86995f76471ce6b2119106ec26f909b7b69e7d43" + integrity sha512-gUxWq42l5ldaRplcKb4Pw5O4XBONWZgz3vxIIXnfIeJj8Jc3wYiq2O4c9xzx/NGbbPEej4rhI62C9eTENwLGNw== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== + dependencies: + ansi-regex "^2.0.0" + +has-bigints@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hdr-histogram-js@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz#0b860534655722b6e3f3e7dca7b78867cf43dcb5" + integrity sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g== + dependencies: + "@assemblyscript/loader" "^0.10.1" + base64-js "^1.2.0" + pako "^1.0.3" + +hdr-histogram-percentiles-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c" + integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw== + +hosted-git-info@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-6.1.1.tgz#629442c7889a69c05de604d52996b74fe6f26d58" + integrity sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w== + dependencies: + lru-cache "^7.5.1" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +htmlparser2@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21" + integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + entities "^4.4.0" + +http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +http-proxy-middleware@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +https-proxy-agent@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +i18n-iso-countries@^7.6.0: + version "7.6.0" + resolved "https://registry.yarnpkg.com/i18n-iso-countries/-/i18n-iso-countries-7.6.0.tgz#4e2eac7043210a5552e7fd116b74d4f36a90b960" + integrity sha512-HPKjOUKS0BkjiY4ayrsuFbu7Ock++pXLs+FAOYl4WfTL5L0ploEH68fiRAP6Zev5g/jvMFt54KcPGJcb942wbg== + dependencies: + diacritics "1.3.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore-walk@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.3.tgz#0fcdb6decaccda35e308a7b0948645dd9523b7bb" + integrity sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA== + dependencies: + minimatch "^9.0.0" + +ignore@5.2.4, ignore@^5.0.4, ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +image-size@~0.5.0: + version "0.5.5" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" + integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +immutable@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" + integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inquirer@8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4" + integrity sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^7.0.0" + +internal-slot@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0, is-core-module@^2.8.1: + version "2.12.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" + integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw== + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g== + dependencies: + path-is-inside "^1.0.1" + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +is-what@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" + integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + +istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.0.tgz#497cbaedc902ec3f31d5d61be804d2364ff9ddad" + integrity sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jake@^10.8.5: + version "10.8.6" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.6.tgz#227a96786a1e035214e0ba84b482d6223d41ef04" + integrity sha512-G43Ub9IYEFfu72sua6rzooi8V8Gz2lkfk48rW20vEWCGizeaEPlKB1Kh8JIA84yQbiAEfqlPmSpGgCKKxH3rDA== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + +jasmine-core@^4.1.0, jasmine-core@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-4.6.0.tgz#6884fc3d5b66bf293e422751eed6d6da217c38f5" + integrity sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ== + +jasmine-core@~2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ== + +jasmine-spec-reporter@~7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz#94b939448e63d4e2bd01668142389f20f0a8ea49" + integrity sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg== + dependencies: + colors "1.4.0" + +jasmine@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw== + dependencies: + exit "^0.1.2" + glob "^7.0.6" + jasmine-core "~2.8.0" + +jasminewd2@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" + integrity sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jiti@^1.18.2: + version "1.19.1" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" + integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== + +js-sdsl@^4.1.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" + integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@4.1.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +js-yaml@^3.10.0, js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-parse-even-better-errors@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz#2cb2ee33069a78870a0c7e3da560026b89669cf7" + integrity sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^2.1.2, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonc-parser@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jszip@^3.1.3: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + +karma-chrome-launcher@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9" + integrity sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q== + dependencies: + which "^1.2.1" + +karma-coverage-istanbul-reporter@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz#f3b5303553aadc8e681d40d360dfdc19bc7e9fe9" + integrity sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw== + dependencies: + istanbul-lib-coverage "^3.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^3.0.6" + istanbul-reports "^3.0.2" + minimatch "^3.0.4" + +karma-jasmine-html-reporter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz#76c26ce40e217dc36a630fbcd7b31c3462948bf2" + integrity sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA== + +karma-jasmine@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-5.1.0.tgz#3af4558a6502fa16856a0f346ec2193d4b884b2f" + integrity sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ== + dependencies: + jasmine-core "^4.1.0" + +karma-source-map-support@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz#58526ceccf7e8730e56effd97a4de8d712ac0d6b" + integrity sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A== + dependencies: + source-map-support "^0.5.5" + +karma@^6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.2.tgz#a983f874cee6f35990c4b2dcc3d274653714de8e" + integrity sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ== + dependencies: + "@colors/colors" "1.5.0" + body-parser "^1.19.0" + braces "^3.0.2" + chokidar "^3.5.1" + connect "^3.7.0" + di "^0.0.1" + dom-serialize "^2.2.1" + glob "^7.1.7" + graceful-fs "^4.2.6" + http-proxy "^1.18.1" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.4.1" + mime "^2.5.2" + minimatch "^3.0.4" + mkdirp "^0.5.5" + qjobs "^1.2.0" + range-parser "^1.2.1" + rimraf "^3.0.2" + socket.io "^4.4.1" + source-map "^0.6.1" + tmp "^0.2.1" + ua-parser-js "^0.7.30" + yargs "^16.1.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +klona@^2.0.4, klona@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== + +launch-editor@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" + integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.7.3" + +less-loader@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-11.1.0.tgz#a452384259bdf8e4f6d5fdcc39543609e6313f82" + integrity sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug== + dependencies: + klona "^2.0.4" + +less@4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/less/-/less-4.1.3.tgz#175be9ddcbf9b250173e0a00b4d6920a5b770246" + integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA== + dependencies: + copy-anything "^2.0.1" + parse-node-version "^1.0.1" + tslib "^2.3.0" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + make-dir "^2.1.0" + mime "^1.4.1" + needle "^3.1.0" + source-map "~0.6.0" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +libphonenumber-js@^1.10.30: + version "1.10.30" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.30.tgz#c0559d6c58dc1a7f189b88b7b23354c98b182848" + integrity sha512-PLGc+xfrQrkya/YK2/5X+bPpxRmyJBHM+xxz9krUdSgk4Vs2ZwxX5/Ow0lv3r9PDlDtNWb4u+it8MY5rZ0IyGw== + +license-webpack-plugin@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz#1e18442ed20b754b82f1adeff42249b81d11aec6" + integrity sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw== + dependencies: + webpack-sources "^3.0.0" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lines-and-columns@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b" + integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.1.tgz#4fb104b599daafd82ef3e1a41fb9265f87e1f576" + integrity sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw== + +loader-utils@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.4.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" + integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.5" + +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +lru-cache@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.1.tgz#c58a93de58630b688de39ad04ef02ef26f1902f1" + integrity sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A== + +magic-string@0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529" + integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.13" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0, make-dir@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-fetch-happen@^10.0.3: + version "10.2.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" + integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w== + dependencies: + agentkeepalive "^4.2.1" + cacache "^16.1.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^7.7.1" + minipass "^3.1.6" + minipass-collect "^1.0.2" + minipass-fetch "^2.0.3" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + socks-proxy-agent "^7.0.0" + ssri "^9.0.0" + +make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.0: + version "11.1.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz#85ceb98079584a9523d4bf71d32996e7e208549f" + integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w== + dependencies: + agentkeepalive "^4.2.1" + cacache "^17.0.0" + http-cache-semantics "^4.1.1" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^7.7.1" + minipass "^5.0.0" + minipass-fetch "^3.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + socks-proxy-agent "^7.0.0" + ssri "^10.0.0" + +material-colors@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" + integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== + +material-design-icons-iconfont@^6.1.1: + version "6.7.0" + resolved "https://registry.yarnpkg.com/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz#55cf0f3d7e4c76e032855b7e810b6e30535eff3c" + integrity sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.12, memfs@^3.4.3: + version "3.5.1" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.5.1.tgz#f0cd1e2bfaef58f6fe09bfb9c2288f07fea099ec" + integrity sha512-UWbFJKvj5k+nETdteFndTpYxdeTMox/ULeqX5k/dpaQJCCFmj5EeKv3dBcyO2xmkRAx2vppRu5dVG7SOtsGOzA== + dependencies: + fs-monkey "^1.0.3" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0, mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@2.7.6: + version "2.7.6" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d" + integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" + integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.0.tgz#bfc8e88a1c40ffd40c172ddac3decb8451503b56" + integrity sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add" + integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA== + dependencies: + minipass "^3.1.6" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-fetch@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.3.tgz#d9df70085609864331b533c960fd4ffaa78d15ce" + integrity sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ== + dependencies: + minipass "^5.0.0" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-json-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" + integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== + dependencies: + jsonparse "^1.3.1" + minipass "^3.0.0" + +minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.0": + version "6.0.1" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.1.tgz#315417c259cb32a1b2fc530c0e7f55c901a60a6d" + integrity sha512-Tenl5QPpgozlOGBiveNYHg2f6y+VpxsXRoIHFUVJuSmTonXRAE6q9b8Mp/O46762/2AlW4ye4Nkyvx0fgWDKbw== + +minizlib@^2.1.1, minizlib@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +moment@^2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== + +mrmime@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" + integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +needle@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44" + integrity sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.6.3" + sax "^1.2.4" + +negotiator@0.6.3, negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +ngx-color@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/ngx-color/-/ngx-color-9.0.0.tgz#7e58da081a3563c53607fc10090a61cfa27eaffc" + integrity sha512-zyAFux+FRI4cACZ7g8DQQsBbNMhqmFkhtUPaxhkiVHhPzWU1iqXP8MqWH6By3guNOCch5oYrYNBWlHToklbdDg== + dependencies: + "@ctrl/tinycolor" "^3.6.0" + material-colors "^1.2.6" + tslib "^2.3.0" + +nice-napi@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b" + integrity sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA== + dependencies: + node-addon-api "^3.0.0" + node-gyp-build "^4.2.2" + +node-addon-api@^3.0.0, node-addon-api@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-gyp-build@^4.2.2, node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +node-gyp@^9.0.0: + version "9.3.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.3.1.tgz#1e19f5f290afcc9c46973d68700cbd21a96192e4" + integrity sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.6" + make-fetch-happen "^10.0.3" + nopt "^6.0.0" + npmlog "^6.0.0" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.2" + which "^2.0.2" + +node-releases@^2.0.12: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +node-releases@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" + integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== + +nopt@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" + integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g== + dependencies: + abbrev "^1.0.0" + +normalize-package-data@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-5.0.0.tgz#abcb8d7e724c40d88462b84982f7cbf6859b4588" + integrity sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q== + dependencies: + hosted-git-info "^6.0.0" + is-core-module "^2.8.1" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +npm-bundled@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7" + integrity sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ== + dependencies: + npm-normalize-package-bin "^3.0.0" + +npm-install-checks@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-6.1.1.tgz#b459b621634d06546664207fde16810815808db1" + integrity sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw== + dependencies: + semver "^7.1.1" + +npm-normalize-package-bin@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" + integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== + +npm-package-arg@10.1.0, npm-package-arg@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1" + integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA== + dependencies: + hosted-git-info "^6.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + validate-npm-package-name "^5.0.0" + +npm-packlist@^7.0.0: + version "7.0.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-7.0.4.tgz#033bf74110eb74daf2910dc75144411999c5ff32" + integrity sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q== + dependencies: + ignore-walk "^6.0.0" + +npm-pick-manifest@8.0.1, npm-pick-manifest@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz#c6acd97d1ad4c5dbb80eac7b386b03ffeb289e5f" + integrity sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA== + dependencies: + npm-install-checks "^6.0.0" + npm-normalize-package-bin "^3.0.0" + npm-package-arg "^10.0.0" + semver "^7.3.5" + +npm-registry-fetch@^14.0.0: + version "14.0.5" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz#fe7169957ba4986a4853a650278ee02e568d115d" + integrity sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA== + dependencies: + make-fetch-happen "^11.0.0" + minipass "^5.0.0" + minipass-fetch "^3.0.0" + minipass-json-stream "^1.0.1" + minizlib "^2.1.2" + npm-package-arg "^10.0.0" + proc-log "^3.0.0" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npmlog@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +nx@16.0.2: + version "16.0.2" + resolved "https://registry.yarnpkg.com/nx/-/nx-16.0.2.tgz#2c820507ca32c851623b414ce3c6d285554f1a70" + integrity sha512-8Z9Bo1D2VbYjyC/F2ONensKjm10snz1UfkzURZiFA+oXikBPldiH1u67TOTpoCYZfyYQg4l6h6EpOaAvHF6Abg== + dependencies: + "@nrwl/tao" "16.0.2" + "@parcel/watcher" "2.0.4" + "@yarnpkg/lockfile" "^1.1.0" + "@yarnpkg/parsers" "^3.0.0-rc.18" + "@zkochan/js-yaml" "0.0.6" + axios "^1.0.0" + chalk "^4.1.0" + cli-cursor "3.1.0" + cli-spinners "2.6.1" + cliui "^7.0.2" + dotenv "~10.0.0" + enquirer "~2.3.6" + fast-glob "3.2.7" + figures "3.2.0" + flat "^5.0.2" + fs-extra "^11.1.0" + glob "7.1.4" + ignore "^5.0.4" + js-yaml "4.1.0" + jsonc-parser "3.2.0" + lines-and-columns "~2.0.3" + minimatch "3.0.5" + npm-run-path "^4.0.1" + open "^8.4.0" + semver "7.3.4" + string-width "^4.2.3" + strong-log-transformer "^2.1.0" + tar-stream "~2.2.0" + tmp "~0.2.1" + tsconfig-paths "^4.1.2" + tslib "^2.3.0" + v8-compile-cache "2.3.0" + yargs "^17.6.2" + yargs-parser "21.1.1" + optionalDependencies: + "@nx/nx-darwin-arm64" "16.0.2" + "@nx/nx-darwin-x64" "16.0.2" + "@nx/nx-linux-arm-gnueabihf" "16.0.2" + "@nx/nx-linux-arm64-gnu" "16.0.2" + "@nx/nx-linux-arm64-musl" "16.0.2" + "@nx/nx-linux-x64-gnu" "16.0.2" + "@nx/nx-linux-x64-musl" "16.0.2" + "@nx/nx-win32-arm64-msvc" "16.0.2" + "@nx/nx-win32-x64-msvc" "16.0.2" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4, object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@8.4.2, open@^8.0.9, open@^8.4.0: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +opentype.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/opentype.js/-/opentype.js-1.3.4.tgz#1c0e72e46288473cc4a4c6a2dc60fd7fe6020d77" + integrity sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw== + dependencies: + string.prototype.codepointat "^0.2.1" + tiny-inflate "^1.0.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +ora@5.4.1, ora@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pacote@15.2.0: + version "15.2.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3" + integrity sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA== + dependencies: + "@npmcli/git" "^4.0.0" + "@npmcli/installed-package-contents" "^2.0.1" + "@npmcli/promise-spawn" "^6.0.1" + "@npmcli/run-script" "^6.0.0" + cacache "^17.0.0" + fs-minipass "^3.0.0" + minipass "^5.0.0" + npm-package-arg "^10.0.0" + npm-packlist "^7.0.0" + npm-pick-manifest "^8.0.0" + npm-registry-fetch "^14.0.0" + proc-log "^3.0.0" + promise-retry "^2.0.1" + read-package-json "^6.0.0" + read-package-json-fast "^3.0.0" + sigstore "^1.3.0" + ssri "^10.0.0" + tar "^6.1.11" + +pako@^1.0.3, pako@~1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-node-version@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + +parse5-html-rewriting-stream@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz#e376d3e762d2950ccbb6bb59823fc1d7e9fdac36" + integrity sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg== + dependencies: + entities "^4.3.0" + parse5 "^7.0.0" + parse5-sax-parser "^7.0.0" + +parse5-sax-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz#4c05064254f0488676aca75fb39ca069ec96dee5" + integrity sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg== + dependencies: + parse5 "^7.0.0" + +parse5@^7.0.0, parse5@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.7.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.9.1.tgz#838566bb22e38feaf80ecd49ae06cd12acd782ee" + integrity sha512-UgmoiySyjFxP6tscZDgWGEAgsW5ok8W3F5CJDnnH2pozwSTGE6eH7vwTotMwATWA2r5xqdkKdxYPkwlJjAI/3g== + dependencies: + lru-cache "^9.1.1" + minipass "^5.0.0 || ^6.0.0" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@2.3.1, picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== + +piscina@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/piscina/-/piscina-3.2.0.tgz#f5a1dde0c05567775690cccefe59d9223924d154" + integrity sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA== + dependencies: + eventemitter-asyncresource "^1.0.0" + hdr-histogram-js "^2.0.1" + hdr-histogram-percentiles-obj "^3.0.0" + optionalDependencies: + nice-napi "^1.0.2" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + +postcss-loader@7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.2.tgz#ac3344ad1f14bb65df135744b7efae4dbdad4301" + integrity sha512-c7qDlXErX6n0VT+LUsW+nwefVtTu3ORtVvK8EXuUIDcxo+b/euYqpuHlJAvePb0Af5e8uMjR/13e0lTuYifaig== + dependencies: + cosmiconfig "^8.1.3" + jiti "^1.18.2" + klona "^2.0.6" + semver "^7.3.8" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" + integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.13" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@8.4.24: + version "8.4.24" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df" + integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.2.14, postcss@^8.4.21: + version "8.4.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" + integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.23: + version "8.4.25" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.25.tgz#4a133f5e379eda7f61e906c3b1aaa9b81292726f" + integrity sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-plugin-organize-imports@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.2.tgz#91993365e017daa5d0d28d8183179834224d8dd1" + integrity sha512-e97lE6odGSiHonHJMTYC0q0iLXQyw0u5z/PJpvP/3vRy6/Zi9kLBwFAbEGjDzIowpjQv8b+J04PDamoUSQbzGA== + +prettier@^2.8.7: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +pretty-bytes@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +proc-log@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" + integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +protobufjs@^7.0.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2" + integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +protractor@~7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/protractor/-/protractor-7.0.0.tgz#c3e263608bd72e2c2dc802b11a772711a4792d03" + integrity sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw== + dependencies: + "@types/q" "^0.0.32" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" + chalk "^1.1.3" + glob "^7.0.3" + jasmine "2.8.0" + jasminewd2 "^2.1.0" + q "1.4.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" + source-map-support "~0.4.0" + webdriver-js-extender "2.1.0" + webdriver-manager "^12.1.7" + yargs "^15.3.1" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +q@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + integrity sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg== + +q@^1.4.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qrcode@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb" + integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg== + dependencies: + dijkstrajs "^1.0.1" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +read-package-json-fast@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" + integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== + dependencies: + json-parse-even-better-errors "^3.0.0" + npm-normalize-package-bin "^3.0.0" + +read-package-json@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-6.0.3.tgz#726116b75e00eac2075240995f05681af4ca7122" + integrity sha512-4QbpReW4kxFgeBQ0vPAqh2y8sXEB3D4t3jsXbJKIhBiF80KT6XRo45reqwtftju5J6ru1ax06A2Gb/wM1qCOEQ== + dependencies: + glob "^10.2.2" + json-parse-even-better-errors "^3.0.0" + normalize-package-data "^5.0.0" + npm-normalize-package-bin "^3.0.0" + +readable-stream@^2.0.1, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reflect-metadata@^0.1.2: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-parser@^2.2.11: + version "2.2.11" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" + integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== + +regexp.prototype.flags@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + functions-have-names "^1.2.3" + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +request@^2.87.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-url-loader@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz#ee3142fb1f1e0d9db9524d539cfa166e9314f795" + integrity sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg== + dependencies: + adjust-sourcemap-loader "^4.0.0" + convert-source-map "^1.7.0" + loader-utils "^2.0.0" + postcss "^8.2.14" + source-map "0.6.1" + +resolve@1.22.2, resolve@^1.14.2: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^3.21.0: + version "3.26.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.26.2.tgz#2e76a37606cb523fc9fef43e6f59c93f86d95e7c" + integrity sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA== + optionalDependencies: + fsevents "~2.3.2" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@7.8.1, rxjs@^7.5.5, rxjs@~7.8.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +rxjs@^6.5.3: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +safevalues@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/safevalues/-/safevalues-0.3.4.tgz#82e846a02b6956d7d40bf9f41e92e13fce0186db" + integrity sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw== + +sass-loader@13.3.1: + version "13.3.1" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-13.3.1.tgz#32ee5791434b9b4dbd1adcce76fcb4cea49cc12c" + integrity sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg== + dependencies: + klona "^2.0.6" + neo-async "^2.6.2" + +sass@1.63.2: + version "1.63.2" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.63.2.tgz#75f7d9a8e67d1d5b98a989507f4d98b6067b1f75" + integrity sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== + dependencies: + https-proxy-agent "^2.2.1" + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^3.1.1, schema-utils@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.2.tgz#36c10abca6f7577aeae136c804b0c741edeadc99" + integrity sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.1.tgz#eb2d042df8b01f4b5c276a2dfd41ba0faab72e8d" + integrity sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +selfsigned@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== + dependencies: + node-forge "^1" + +semver-dsl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0" + integrity sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng== + dependencies: + semver "^5.3.0" + +semver@7.3.4: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + +semver@7.5.3: + version "7.5.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" + integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== + dependencies: + lru-cache "^6.0.0" + +semver@^5.3.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.0.0, semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: + version "7.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec" + integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" + integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== + +sigstore@^1.3.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-1.5.2.tgz#8d4c2a549341211cb08c687999843edc48c1a94c" + integrity sha512-X95v6xAAooVpn7PaB94TDmFeSO5SBfCtB1R23fvzr36WTfjtkiiyOeei979nbTjc8nzh6FSLeltQZuODsm1EjQ== + dependencies: + "@sigstore/protobuf-specs" "^0.1.0" + make-fetch-happen "^11.0.1" + tuf-js "^1.1.3" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socket.io-adapter@~2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12" + integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA== + dependencies: + ws "~8.11.0" + +socket.io-parser@~4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" + integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.4.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.6.1.tgz#62ec117e5fce0692fa50498da9347cfb52c3bc70" + integrity sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + debug "~4.3.2" + engine.io "~6.4.1" + socket.io-adapter "~2.5.2" + socket.io-parser "~4.2.1" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +socks-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" + integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== + dependencies: + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" + +socks@^2.6.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.1.tgz#72f00d05f5d1f90f80974eda781cbd7107c125f2" + integrity sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA== + dependencies: + abab "^2.0.6" + iconv-lite "^0.6.3" + source-map-js "^1.0.2" + +source-map-support@0.5.21, source-map-support@^0.5.5, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.4.0: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +sprintf-js@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +sshpk@^1.7.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^10.0.0: + version "10.0.4" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.4.tgz#5a20af378be586df139ddb2dfb3bf992cf0daba6" + integrity sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ== + dependencies: + minipass "^5.0.0" + +ssri@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" + integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q== + dependencies: + minipass "^3.1.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +streamroller@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" + integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.codepointat@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc" + integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg== + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strong-log-transformer@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" + integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== + dependencies: + duplexer "^0.1.1" + minimist "^1.2.0" + through "^2.3.4" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-observable@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tar-stream@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar@^6.1.11, tar@^6.1.2: + version "6.1.14" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.14.tgz#e87926bec1cfe7c9e783a77a79f3e81c1cfa3b66" + integrity sha512-piERznXu0U7/pW7cdSn7hjqySIVTYT6F76icmFk7ptU7dDYlXTm5r9A6K04R2vU3olYgoKeo1Cg3eeu5nhftAw== + 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" + +terser-webpack-plugin@^5.3.7: + version "5.3.8" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz#415e03d2508f7de63d59eca85c5d102838f06610" + integrity sha512-WiHL3ElchZMsK27P8uIUh4604IgJyAW47LVXGbEoB21DbQcZ+OuMpGjVYnEUaqcWM6dO8uS2qUbA7LSCWqvsbg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@5.17.7: + version "5.17.7" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.7.tgz#2a8b134826fe179b711969fd9d9a0c2479b2a8c3" + integrity sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +terser@^5.16.8: + version "5.17.4" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.4.tgz#b0c2d94897dfeba43213ed5f90ed117270a2c696" + integrity sha512-jcEKZw6UPrgugz/0Tuk/PVyLAPfMBJf5clnGueo45wTweoV8yh7Q7PEkhkJ5uuUbC7zAxEcG3tqNr1bstkQ8nw== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@0.2.0, text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through@X.X.X, through@^2.3.4, through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tiny-inflate@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" + integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== + +tinycolor2@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" + integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== + +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + integrity sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w== + dependencies: + os-tmpdir "~1.0.1" + +tmp@0.2.1, tmp@^0.2.1, tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +tsconfig-paths@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" + integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== + +tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tuf-js@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-1.1.6.tgz#ad3e7a20237b83b51c2a8f9d1ddf093279a10fc2" + integrity sha512-CXwFVIsXGbVY4vFiWF7TJKWmlKJAT8TWkH4RmiohJRcDJInix++F0dznDmoVbtJNzZ8yLprKUG4YrDIhv3nBMg== + dependencies: + "@tufjs/models" "1.0.4" + debug "^4.3.4" + make-fetch-happen "^11.1.0" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typed-assert@^1.0.8: + version "1.0.9" + resolved "https://registry.yarnpkg.com/typed-assert/-/typed-assert-1.0.9.tgz#8af9d4f93432c4970ec717e3006f33f135b06213" + integrity sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg== + +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +ua-parser-js@^0.7.30: + version "0.7.35" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.35.tgz#8bda4827be4f0b1dda91699a29499575a1f1d307" + integrity sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +unique-filename@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" + integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A== + dependencies: + unique-slug "^3.0.0" + +unique-filename@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" + integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== + dependencies: + unique-slug "^4.0.0" + +unique-slug@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9" + integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w== + dependencies: + imurmurhash "^0.1.4" + +unique-slug@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" + integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== + dependencies: + imurmurhash "^0.1.4" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.10, update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + +v8-compile-cache@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz#f16afd48318e6f90a1ec101377fa0384cfc8c713" + integrity sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ== + dependencies: + builtins "^5.0.0" + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vite@4.3.9: + version "4.3.9" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d" + integrity sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg== + dependencies: + esbuild "^0.17.5" + postcss "^8.4.23" + rollup "^3.21.0" + optionalDependencies: + fsevents "~2.3.2" + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + +walkdir@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" + integrity sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ== + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== + dependencies: + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" + +webdriver-manager@^12.1.7: + version "12.1.9" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.9.tgz#8d83543b92711b7217b39fef4cda958a4703d2df" + integrity sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ== + dependencies: + adm-zip "^0.5.2" + chalk "^1.1.1" + del "^2.2.0" + glob "^7.0.3" + ini "^1.3.4" + minimist "^1.2.0" + q "^1.4.1" + request "^2.87.0" + rimraf "^2.5.2" + semver "^5.3.0" + xml2js "^0.4.17" + +webpack-dev-middleware@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz#6bbc257ec83ae15522de7a62f995630efde7cc3d" + integrity sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ== + dependencies: + colorette "^2.0.10" + memfs "^3.4.12" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz#87ba9006eca53c551607ea0d663f4ae88be7af21" + integrity sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.1" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + launch-editor "^2.6.0" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.1" + ws "^8.13.0" + +webpack-merge@5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.0.0, webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack-subresource-integrity@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz#8b7606b033c6ccac14e684267cb7fb1f5c2a132a" + integrity sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q== + dependencies: + typed-assert "^1.0.8" + +webpack@5.86.0: + version "5.86.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.86.0.tgz#b0eb81794b62aee0b7e7eb8c5073495217d9fc6d" + integrity sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.14.1" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.2" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1" + integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.13.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + +ws@~8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + +xml2js@^0.4.17: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@21.1.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@17.7.2, yargs@^17.2.1, yargs@^17.6.2, yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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" + +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zone.js@~0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16" + integrity sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg== + +zone.js@~0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.13.0.tgz#4c735cb8ef49312b58c0ad13451996dc2b202a6d" + integrity sha512-7m3hNNyswsdoDobCkYNAy5WiUulkMd3+fWaGT9ij6iq3Zr/IwJo4RMCYPSDjT+r7tnPErmY9sZpKhWQ8S5k6XQ== + dependencies: + tslib "^2.3.0" diff --git a/docs/apis/assets/assets.md b/docs/apis/assets/assets.md new file mode 100755 index 000000000..28bec4fa1 --- /dev/null +++ b/docs/apis/assets/assets.md @@ -0,0 +1,259 @@ +--- +title: zitadel/assets +--- + +## AssetsService + + + + + +### UploadDefaultLabelPolicyFont() + +> UploadDefaultLabelPolicyFont() + +POST: /instance/policy/label/font + + + +### GetDefaultLabelPolicyFont() + +> GetDefaultLabelPolicyFont() + +GET: /instance/policy/label/font + + + +### GetPreviewDefaultLabelPolicyFont() + +> GetPreviewDefaultLabelPolicyFont() + +GET: /instance/policy/label/font/_preview + + + + + +### UploadDefaultLabelPolicyIcon() + +> UploadDefaultLabelPolicyIcon() + +POST: /instance/policy/label/icon + +### UploadDefaultLabelPolicyIcon() + +> UploadDefaultLabelPolicyIconDark() + +POST: /instance/policy/label/icon/dark + + + +### GetDefaultLabelPolicyIcon() + +> GetDefaultLabelPolicyIcon() + +GET: /instance/policy/label/icon + +### GetDefaultLabelPolicyIcon() + +> GetDefaultLabelPolicyIconDark() + +GET: /instance/policy/label/icon/dark + + + +### GetPreviewDefaultLabelPolicyIcon() + +> GetPreviewDefaultLabelPolicyIcon() + +GET: /instance/policy/label/icon/_preview + +### GetPreviewDefaultLabelPolicyIcon() + +> GetPreviewDefaultLabelPolicyIconDark() + +GET: /instance/policy/label/icon/dark/_preview + + + + + +### UploadDefaultLabelPolicyLogo() + +> UploadDefaultLabelPolicyLogo() + +POST: /instance/policy/label/logo + +### UploadDefaultLabelPolicyLogo() + +> UploadDefaultLabelPolicyLogoDark() + +POST: /instance/policy/label/logo/dark + + + +### GetDefaultLabelPolicyLogo() + +> GetDefaultLabelPolicyLogo() + +GET: /instance/policy/label/logo + +### GetDefaultLabelPolicyLogo() + +> GetDefaultLabelPolicyLogoDark() + +GET: /instance/policy/label/logo/dark + + + +### GetPreviewDefaultLabelPolicyLogo() + +> GetPreviewDefaultLabelPolicyLogo() + +GET: /instance/policy/label/logo/_preview + +### GetPreviewDefaultLabelPolicyLogo() + +> GetPreviewDefaultLabelPolicyLogoDark() + +GET: /instance/policy/label/logo/dark/_preview + + + + + + + +### UploadOrgLabelPolicyFont() + +> UploadOrgLabelPolicyFont() + +POST: /org/policy/label/font + + + +### GetOrgLabelPolicyFont() + +> GetOrgLabelPolicyFont() + +GET: /org/policy/label/font + + + +### GetPreviewOrgLabelPolicyFont() + +> GetPreviewOrgLabelPolicyFont() + +GET: /org/policy/label/font/_preview + + + + + +### UploadOrgLabelPolicyIcon() + +> UploadOrgLabelPolicyIcon() + +POST: /org/policy/label/icon + +### UploadOrgLabelPolicyIcon() + +> UploadOrgLabelPolicyIconDark() + +POST: /org/policy/label/icon/dark + + + +### GetOrgLabelPolicyIcon() + +> GetOrgLabelPolicyIcon() + +GET: /org/policy/label/icon + +### GetOrgLabelPolicyIcon() + +> GetOrgLabelPolicyIconDark() + +GET: /org/policy/label/icon/dark + + + +### GetPreviewOrgLabelPolicyIcon() + +> GetPreviewOrgLabelPolicyIcon() + +GET: /org/policy/label/icon/_preview + +### GetPreviewOrgLabelPolicyIcon() + +> GetPreviewOrgLabelPolicyIconDark() + +GET: /org/policy/label/icon/dark/_preview + + + + + +### UploadOrgLabelPolicyLogo() + +> UploadOrgLabelPolicyLogo() + +POST: /org/policy/label/logo + +### UploadOrgLabelPolicyLogo() + +> UploadOrgLabelPolicyLogoDark() + +POST: /org/policy/label/logo/dark + + + +### GetOrgLabelPolicyLogo() + +> GetOrgLabelPolicyLogo() + +GET: /org/policy/label/logo + +### GetOrgLabelPolicyLogo() + +> GetOrgLabelPolicyLogoDark() + +GET: /org/policy/label/logo/dark + + + +### GetPreviewOrgLabelPolicyLogo() + +> GetPreviewOrgLabelPolicyLogo() + +GET: /org/policy/label/logo/_preview + +### GetPreviewOrgLabelPolicyLogo() + +> GetPreviewOrgLabelPolicyLogoDark() + +GET: /org/policy/label/logo/dark/_preview + + + + + + + +### UploadMyUserAvatar() + +> UploadMyUserAvatar() + +POST: /users/me/avatar + + + +### GetMyUserAvatar() + +> GetMyUserAvatar() + +GET: /users/me/avatar + + + + diff --git a/docs/docs/apis/actions/external-authentication.md b/docs/docs/apis/actions/external-authentication.md index f26f55af8..5d5606670 100644 --- a/docs/docs/apis/actions/external-authentication.md +++ b/docs/docs/apis/actions/external-authentication.md @@ -36,9 +36,9 @@ The first parameter contains the following fields - `appendMetadata(string, Any)` The first parameter represents the key and the second a value which will be stored - `setFirstName(string)` - Sets the first name + Sets the given name - `setLastName(string)` - Sets the last name + Sets the family name - `setNickName(string)` Sets the nickname - `setDisplayName(string)` @@ -75,9 +75,9 @@ A user selected **Register** on the overview page after external authentication. - `metadata` Array of [*metadata*](./objects#metadata-with-value-as-bytes). This function is deprecated, please use `api.v1.user.appendMetadata` - `setFirstName(string)` - Sets the first name + Sets the given name - `setLastName(string)` - Sets the last name + Sets the family name - `setNickName(string)` Sets the nick name - `setDisplayName(string)` diff --git a/docs/docs/examples/login/nextjs-b2b.md b/docs/docs/examples/login/nextjs-b2b.md index 4f64cc683..7dbd33f1f 100644 --- a/docs/docs/examples/login/nextjs-b2b.md +++ b/docs/docs/examples/login/nextjs-b2b.md @@ -35,7 +35,7 @@ Open the Console (`https://{YourDomain}.zitadel.cloud/ui/console/projects`) and Then on the project detail page click on new application and enter a name for this app. Let's call this one `portal-web`. Select `Web`, continue, `CODE`, then enter `http://localhost:3000/api/auth/callback/zitadel` for the redirect, and `http://localhost:3000` for the post redirect. Then press on `create`. -Because the requests from your NextJS application to ZITADEL are made on the server side, you can safely select `CODE`. With this you still get a secret which is then usable alongside PKCE. Your secret never gets exposed on the browser since it is kept in your NextJS server. +Because the requests from your NextJS application to ZITADEL are made on the server side, you can safely select `CODE`. You will get a secret at the end of the stepper. With NextAuth your secret never gets exposed on the browser since it is kept in your NextJS server. Copy the "Resource Id" of the project `Portal` as you will need this in your environment configuration file later. diff --git a/docs/docs/examples/login/nextjs.md b/docs/docs/examples/login/nextjs.md index cde4823cb..5362a3391 100644 --- a/docs/docs/examples/login/nextjs.md +++ b/docs/docs/examples/login/nextjs.md @@ -19,7 +19,7 @@ yarn install then to run the app: ```bash -npm run dev +yarn dev ``` then open [http://localhost:3000](http://localhost:3000) with your browser to see the result. @@ -28,10 +28,11 @@ then open [http://localhost:3000](http://localhost:3000) with your browser to se Before we can start building our application, we have to do a few configuration steps in ZITADEL Console. You will need to provide some information about your app. + Navigate to your Project, then add a new application at the top of the page. Select Web application type and continue. -We recommend you use [Authorization Code](/apis/openidoauth/grant-types#authorization-code) in combination with [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all web applications. -As the requests from your application to ZITADEL are made on NextJS serverside, you can select `CODE` in the next step. This makes sure you still get a secret which is then used in combination with PKCE. Note that the secret never gets exposed on the browser and is therefore kept in a confidential environment. +We use [Authorization Code](/apis/openidoauth/grant-types#authorization-code)for our NextJS application. +Select `CODE` in the next step. This makes sure you still get a secret. Note that the secret never gets exposed on the browser and is therefore kept in a confidential environment. ![Create app in console](/img/nextjs/app-create.png) @@ -135,15 +136,11 @@ ZitadelProvider({ ... ``` -We recommend using the Authentication Code flow secured by PKCE for the Authentication flow. -To be able to connect to ZITADEL, navigate to your Console Projects, create or select an existing project and add your app selecting WEB, then PKCE, and then add `http://localhost:3000/api/auth/callback/zitadel` as redirect url to your app. - +To be able to connect to ZITADEL, make sure to add `http://localhost:3000/api/auth/callback/zitadel` as redirect url to your app. For simplicity reasons we set the default to the one that next-auth provides us. You'll be able to change the redirect later if you want to. Hit Create, then in the detail view of your application make sure to enable dev mode. Dev mode ensures that you can start an auth flow from a non https endpoint for testing. -> Note that we get a clientId but no clientSecret because it is not needed for our authentication flow. - Now go to Token settings and check the checkbox for **User Info inside ID Token** to get your users name directly on authentication. ### Environment diff --git a/docs/docs/guides/integrate/identity-providers/migrate.mdx b/docs/docs/guides/integrate/identity-providers/migrate.mdx new file mode 100644 index 000000000..dc9cbb096 --- /dev/null +++ b/docs/docs/guides/integrate/identity-providers/migrate.mdx @@ -0,0 +1,48 @@ +--- +title: Migrate from Generic Provider to specific Identity Provider +sidebar_label: Migrate IDP +--- + +## Migrate Generic OIDC Provider + +You can migrate from a generic OIDC provider to the following supported templates: +- AzureAD +- Google + +To migrate, you either use the [Migrate Generic OIDC Identity Provider (Instance)](/docs/apis/resources/admin/admin-service-migrate-generic-oidc-provider#migrate-generic-oidc-identity-provider) or [Migrate Generic OIDC Identity Provider (Organization)](/docs/apis/resources/mgmt/management-service-migrate-generic-oidc-provider#migrate-generic-oidc-identity-provider) API request. +These calls change the type of the provider and don't delete any linked users. + +:::note Linked users will not notice the change and be able to login as usual. +::: + +### Google Configuration + +The available configuration is described in [Google Configuration](./google). + +### AzureAD Configuration + +The available configuration is described in [AzureAD Configuration](./azure-ad). + +## Migrate with Terraform +Please note that you only have to perform this migration if you already have an existing IDP with linked users, that should not loose the connection to the provider. +If that isn't your case please just add a new provider from scratch. +To migrate to a specific provider, you need to follow a few essential steps: +1. Create a desired IDP as Terraform resource for example [Google](https://registry.terraform.io/providers/zitadel/zitadel/latest/docs/resources/idp_google). +2. Make the corresponding API call to [migrate the IDP](./migrate#google-configuration), save the ID of the IDP for the import +3. Before applying the Terraform resources again, import the new IDP resource. +```bash +#resource "zitadel_idp_google" "google" { +# name = "Google" +# client_id = "182902..." +# client_secret = "GOCSPX-*****" +# scopes = ["openid", "profile", "email"] +# is_linking_allowed = false +# is_creation_allowed = true +# is_auto_creation = false +# is_auto_update = true +#} + +# terraform import zitadel_idp_google.*resource_name* *id*:*client_secret* +terraform import zitadel_idp_google.google 222302827723096428:GOCSPX-***** + +You have now migrated your provider and you should be able to apply the resource again. There should be no changes and the IDP is maintained by Terraform again. \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/_browser_register_webauthn.mdx b/docs/docs/guides/integrate/login-ui/_browser_register_webauthn.mdx new file mode 100644 index 000000000..d5570a3e0 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/_browser_register_webauthn.mdx @@ -0,0 +1,12 @@ +Now that you have started the registration within ZITADEL, you have to register the credentials in the browser. +This requires a call to the browser api and looks something like the following. +Make sure to send the public key credential creation options you got in the previous request from ZITADEL. + +```bash +const credential = await navigator.credentials.create({ + publicKey: publicKeyCredentialCreationOptions +}); +``` + +For more information about WebAuthN and registering credential flow, read the following guide: +[Registering a WebAuthN Credentials](https://webauthn.guide/#registration) \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/_list-mfa-options.mdx b/docs/docs/guides/integrate/login-ui/_list-mfa-options.mdx new file mode 100644 index 000000000..ec454bc5c --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/_list-mfa-options.mdx @@ -0,0 +1,46 @@ +Your user has successfully authenticated, and now you ask him if he wants to setup MFA to have a more secure account. +When he starts the configuration, first you want him to show the possible methods. +You can either list it implicitly or call the settings service from ZITADEL to get what is configured on the login settings. + +More detailed information about the API: [Get Login Settings Documentation](/apis/resources/settings_service/settings-service-get-login-settings) + +Request Example: + +```bash +curl --request GET \ + --url https://$ZITADEL_DOMAIN/v2alpha/settings/login \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' +``` + +Response Example: +The relevant part for the list is the second factor and multi factor list. + +```bash +{ + "details": { + "sequence": "293", + "changeDate": "2023-03-29T14:16:55.570482Z", + "resourceOwner": "163840776835432705" + }, + "settings": { + "allowUsernamePassword": true, + "allowRegister": true, + "allowExternalIdp": true, + "passkeysType": "PASSKEYS_TYPE_ALLOWED", + "passwordCheckLifetime": "864000s", + "externalLoginCheckLifetime": "864000s", + "mfaInitSkipLifetime": "2592000s", + "secondFactorCheckLifetime": "64800s", + "multiFactorCheckLifetime": "43200s", + "secondFactors": [ + "SECOND_FACTOR_TYPE_OTP", + "SECOND_FACTOR_TYPE_U2F" + ], + "multiFactors": [ + "MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION" + ], + "resourceOwnerType": "RESOURCE_OWNER_TYPE_ORG" + } +} +``` \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/external-login.mdx b/docs/docs/guides/integrate/login-ui/external-login.mdx index 81da1dcae..fa84303d3 100644 --- a/docs/docs/guides/integrate/login-ui/external-login.mdx +++ b/docs/docs/guides/integrate/login-ui/external-login.mdx @@ -96,13 +96,13 @@ curl --request POST \ "idpId": "218528353504723201", "rawInformation": { "User": { - "email": "fabienne@rootd.ch", + "email": "minni@mouse.com", "email_verified": true, - "family_name": "Bühler", - "given_name": "Fabienne", - "hd": "rootd.ch", + "family_name": "Mouse", + "given_name": "Minnie", + "hd": "mouse.com", "locale": "de", - "name": "Fabienne Bühler", + "name": "Minnie Mouse", "picture": "https://lh3.googleusercontent.com/a/AAcKTtf973Q6NH8KzKTMEZELPU9lx45WpQ9FRBuxFdPb=s96-c", "sub": "111392805975715856637" } diff --git a/docs/docs/guides/integrate/login-ui/mfa.mdx b/docs/docs/guides/integrate/login-ui/mfa.mdx new file mode 100644 index 000000000..c2ae9d80e --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/mfa.mdx @@ -0,0 +1,191 @@ +--- +title: Multi-Factor (MFA) +sidebar_label: Multi-Factor (MFA) +--- + +import MfaOptions from './_list-mfa-options.mdx'; +import BrowserRegisterWebAuthN from './_browser_register_webauthn.mdx'; + + +Multi-factor authentication (MFA) is a multi-step account authentication which requires to user to enter more than only the password. +It is highly recommended to use MFA or [Passkeys](./passkey) to make your user accounts more secure. + +ZITADEL supports two different Methods: +- Time-based one time password (TOTP), which are Authenticator apps like Google/Microsoft Authenticator, Authy, etc +- Universal Second Factor (U2F), which is authentication with your device like Windows Hello, Apple FaceID, Fingerprint, FIDO2 keys, Yubikey, etc. + +## TOTP Registration + +### Flow + +![Register TOTP](/img/guides/login-ui/register-totp-flow.png) + +### List the Possible Methods + + + +### Start TOTP Registration + +The user has selected to setup Time-based One-Time-Password (TOTP). +To show the user the QR to register TOTP with his Authenticator App like Google/Microsoft Authenticator or Authy you have to start the registration on the ZITADEL API. +Generate the QR Code with the URI from the response. +For users that do not have a QR Code reader make sure to also show the secret, to enable manual configuration. + +More detailed information about the API: [Start TOTP Registration Documentation](/apis/resources/user_service/user-service-register-totp) + +Request Example: + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/totp \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' + --header 'Content-Type: application/json' \ + --data '{}' +``` + +Response Example: + +```bash +{ + "details": { + "sequence": "2", + "changeDate": "2023-06-28", + "resourceOwner": "69629023906488334" + }, + "uri": "otpauth://totp/ZITADEL:minni-mouse@mouse.com?algorithm=SHA1&digits=6&issuer=ZITADEL&period=30&secret=TJOPWSDYILLHXFV4MLKNNJOWFG7VSDCK", + "secret": "TJOPWSDYILLHXFV4MLKNNJOWFG7VSDCK" +} +``` + +### Verify TOTP Registration + +When the user has added the account to his authenticator app, he has to enter the code from the App to finish the registration. +This code has to be sent to the verify endpoint in ZITADEL. + +More detailed information about the API: [Verify TOTP Documentation](/apis/resources/user_service/user-service-verify-totp-registration) + +Request Example: + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/totp/_verify \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' + --header 'Content-Type: application/json' \ + --data '{ + "code": "123456" +}' +``` + +## U2F Registration + +### Flow + +![Register U2F](/img/guides/login-ui/register-u2f-flow.png) + +### List the Possible Methods + + + +### Start U2F Registration + +The user has selected to setup Universal Second Factor (U2F). +To be able to authenticate in the browser you have to start the u2f registration within ZITADEL. + +More detailed information about the API: [Start U2F Registration Documentation](/apis/resources/user_service/user-service-register-u-2-f) + +Request Example: + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/u2f \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' + --header 'Content-Type: application/json' \ + --data '{ + "domain": "acme.com" + }' +``` + +Response Example: + +```bash +{ + "details": { + "sequence": "2", + "changeDate": "2023-07-03", + "resourceOwner": "69629023906488334" + }, + "u2fId": "163840776835432705", + "publicKeyCredentialCreationOptions": { + "publicKey": { + "attestation": "none", + "authenticatorSelection": { + "userVerification": "required" + }, + "challenge": "XaMYwWOZ5hj6pwtwJJlpcI-ExkO5TxevBMG4R8DoKQQ", + "excludeCredentials": [ + { + "id": "tVp1QfYhT8DkyEHVrv7blnpAo2YJzbZgZNBf7zPs6CI", + "type": "public-key" + } + ], + "pubKeyCredParams": [ + { + "alg": -7, + "type": "public-key" + } + ], + "rp": { + "id": "localhost", + "name": "ZITADEL" + }, + "timeout": 300000, + "user": { + "displayName": "Minie Mouse", + "id": "MjE1NTk4MDAwNDY0OTk4OTQw", + "name": "minie-mouse" + } + } + } +} +``` + +### Register new U2F on current device + + + +### Verify U2F Registration + +In the next request you have to verify the U2F within ZITADEL. +Include the public key credential you got from the browser in your request. +You can give the U2F a name, which makes it easier for the user to identify the registered authentication methods. +Example: Google Pixel, iCloud Keychain, Yubikey, etc + +More detailed information about the API: [Verify U2F Documentation](/apis/resources/user_service/user-service-verify-u-2-f-registration) + +Example Request: + +```bash + +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/u2f/$PASSKEY_ID \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "publicKeyCredential": { + "type": "public-key", + "id": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00", + "rawId": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00", + "response": { + "attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgRKS3VpeE9tfExXRzkoUKnG4rQWPvtSSt4YtDGgTx32oCIQDPey-2YJ4uIg-QCM4jj6aE2U3tgMFM_RP7Efx6xRu3JGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAADju76085Yhmlt1CEOHkwLQAIKWsFWqxeMT8SxZnwp0ZMF1nk6yhs2m3AIvdixCNVgtNpQECAyYgASFYIMGUDSP2FAQn2MIfPMy7cyB_Y30VqixVgGULTBtFjfRiIlggjUGfQo3_-CrMmH3S-ZQkFKWKnNBQEAMkFtG-9A4zqW0", + "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiQlhXdHh0WGxJeFZZa0pHT1dVaUVmM25zby02aXZKdWw2YmNmWHdMVlFIayIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAifQ" + } + }, + "tokenName": "Google Pixel" +}' +``` + +You have successfully registered a new U2F to the user. \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/passkey.mdx b/docs/docs/guides/integrate/login-ui/passkey.mdx new file mode 100644 index 000000000..bec0a2d60 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/passkey.mdx @@ -0,0 +1,313 @@ +--- +title: Passkeys +sidebar_label: Passkeys +--- + +Passkeys are a replacement for passwords that provide faster, easier, and more secure sign-ins to websites and apps even across multiple devices. +Unlike passwords, passkeys are phishing-resistant and can improve the user experience and security at the same time. +Passkeys and there underlying protocols are a standard defined by the [FIDO Standard](https://fidoalliance.org/) . + +## Register Passkey + +### Flow + +![Passkey Registration](/img/guides/login-ui/passkey-registration-flow.png) + +There are two options to onboard users with passkeys: +1. You send the user a link (email, sms, ...) with an embedded code, so the user is able to register passkey on any capable device +2. You start the passkey registration directly on the current device used by a user + +### Send Registration Link + +When you want to send a link to your user, that enables him to register a new passkey device, you can choose if ZITADEL sends the code or ZITADEL can return the code in the API response. This way you can send a link through any channel of your choice (email, sms, phone, in-person, postal, ...). + +If you asked ZITADEL to send the link to the user please make sure to populate the link with the needed values that point towards your registration UI. + +More detailed information about the API: [Send Registration Link Documentation](/apis/resources/user_service/user-service-create-passkey-registration-link) + +Request Example: +Send either the sendLink or the returnCode (empty message) in the request body, depending on the use case you have. + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/passkeys/registration_link \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "sendLink": { + "urlTemplate": "https://example.com/passkey/register?userID={{.UserID}}&orgID={{.OrgID}}&codeID={{.CodeID}}&code={{.Code}}" + }, + "returnCode": {} +}' +``` + +Response Example: +The code is only filled if returnCode has been requested in the Request.Passkey + +```bash +{ + "details": { + "sequence": "632", + "changeDate": "2023-06-28T08:09:51.257699Z", + "resourceOwner": "163840776835432705" + }, + "code": { + "id": "220526087715684609", + "code": "2KEpIeQGSBBd" + } +} +``` + +### Start Passkey Registration + +When starting the passkey registration you can optionally send the registration code from the step above to ZITADEL to pair it with a specific user. + +By specifying the authenticator type you can choose if the passkey should be cross platform or not. Per default all types are allowed: +- PASSKEY_AUTHENTICATOR_UNSPECIFIED +- PASSKEY_AUTHENTICATOR_PLATFORM +- PASSKEY_AUTHENTICATOR_CROSS_PLATFORM + +The API response will provide you the public key credential options, this will be used by the browser to obtain a signed challenge. + +More detailed information about the API: [Start Passkey Registration Documentation](/apis/resources/user_service/user-service-register-passkey) + +Request Example: +The code only has to be filled if the user did get a registration code. + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/passkeys \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "code": { + "id": "220526087715684609", + "code": "2KEpIeQGSBBd" + }, + "authenticator": "PASSKEY_AUTHENTICATOR_UNSPECIFIED" +}' +``` + +Response Example: + +```bash +{ + "details": { + "sequence": "633", + "changeDate": "2023-06-28T08:10:26.725981Z", + "resourceOwner": "163840776835432705" + }, + "passkeyId": "220526147258024193", + "publicKeyCredentialCreationOptions": { + "publicKey": { + "attestation": "none", + "authenticatorSelection": { + "userVerification": "required" + }, + "challenge": "JM1uLbVQR2xZJ210DA7E-3j0Cd9rHKUSmc8NyIJBtAY", + "pubKeyCredParams": [ + { + "alg": -7, + "type": "public-key" + }, + { + "alg": -35, + "type": "public-key" + }, + { + "alg": -36, + "type": "public-key" + }, + { + "alg": -257, + "type": "public-key" + }, + { + "alg": -258, + "type": "public-key" + }, + { + "alg": -259, + "type": "public-key" + }, + { + "alg": -37, + "type": "public-key" + }, + { + "alg": -38, + "type": "public-key" + }, + { + "alg": -39, + "type": "public-key" + }, + { + "alg": -8, + "type": "public-key" + } + ], + "rp": { + "id": "example.domain.com", + "name": "ZITADEL" + }, + "timeout": 300000, + "user": { + "displayName": "Minnie Mouse", + "id": "MjE4NjYyNTk2OTE4NjQwODk3", + "name": "minni-mouse@mouse.com" + } + } + } +} +``` + +### Register new Passkey on current device + + + +### Verify Passkey in ZITADEL + +In the next request you have to verify the Passkey within ZITADEL. +Include the public key credential you got from the browser in your request. +You can give the Passkey a name, which makes it easier for the user to identify the registered authentication methods. +Example: Google Pixel, iCloud Keychain, Yubikey, etc + +More detailed information about the API: [Verify Passkey Registration Documentation](/apis/resources/user_service/user-service-verify-passkey-registration) + +Example Request: + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/passkeys/$PASSKEY_ID \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "publicKeyCredential": { + "type": "public-key", + "id": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00", + "rawId": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00", + "response": { + "attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgRKS3VpeE9tfExXRzkoUKnG4rQWPvtSSt4YtDGgTx32oCIQDPey-2YJ4uIg-QCM4jj6aE2U3tgMFM_RP7Efx6xRu3JGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAADju76085Yhmlt1CEOHkwLQAIKWsFWqxeMT8SxZnwp0ZMF1nk6yhs2m3AIvdixCNVgtNpQECAyYgASFYIMGUDSP2FAQn2MIfPMy7cyB_Y30VqixVgGULTBtFjfRiIlggjUGfQo3_-CrMmH3S-ZQkFKWKnNBQEAMkFtG-9A4zqW0", + "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiQlhXdHh0WGxJeFZZa0pHT1dVaUVmM25zby02aXZKdWw2YmNmWHdMVlFIayIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAifQ" + } + }, + "passkeyName": "Google Pixel" +}' +``` + +You have successfully registered a new passkey to the user. +Next step is to authenticate the user with the new registered passkey. + +## Login with Passkey + +### Flow + +![Passkey Login](/img/guides/login-ui/passkey-login-flow.png) + + +### Create Session + +First step is to ask the user for his username and create a new session with the ZITADEL API. +When creating the new session make sure to include the challenge for passkey. +The response will include the public key credential request options for the passkey in the challenges. + +More detailed information about the API: [Create Session Documentation](/apis/resources/session_service/session-service-create-session) + +Example Request: +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/sessions \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "checks": { + "user": { + "loginName": "minni-mouse@mouse.com" + } + }, + "metadata": {}, + "challenges": [ + "CHALLENGE_KIND_PASSKEY" + ] +}' +``` + +Example Response: +```bash +{ + "details": { + "sequence": "2", + "changeDate": "2023-06-27", + "resourceOwner": "69629023906488334" + }, + "sessionId": "d654e6ba-70a3-48ef-a95d-37c8d8a7901a", + "sessionToken": "string", + "challenges": { + "passkey": { + "publicKeyCredentialRequestOptions": { + "publicKey": { + "allowCredentials": [ + { + "id": "ATmqBg-99qyOZk2zloPdJQyS2R7IkFT7v9Hoos_B_nM", + "type": "public-key" + } + ], + "challenge": "GAOHYz2jE69kJMYo6Laij8yWw9-dKKgbViNhfuy0StA", + "rpId": "example.domain.com", + "timeout": 300000, + "userVerification": "required" + } + } + } + } +} +``` + +### Signing in Browser + +After starting the passkey authentication on the side of ZITADEL you have to challenge the browser. +To do this you need to call the browser API to get the credentials. +Make sure to send the public key credential request options you got from ZITADEL. + +```bash +const credential = await navigator.credentials.get({ + publicKey: publicKeyCredentialRequestOptions +}); +``` + +Read the [WebAuthN Guide](https://webauthn.guide/#authentication) for more information about "Authenticating with a WebAuthN Credential". + +### Update Session with Passkey + +Now that you have successfully authenticated in the browser, you can update the session of the user. +Fill the passkey checks with the credential assertion data you get from the browser. + +More detailed information about the API: [Update Session Documentation](/apis/resources/session_service/session-service-set-session) + +Example Request: + +```bash +curl --request PATCH \ + --url https://$ZITADEL_DOMAIN/v2alpha/sessions/218480890961985793 \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "sessionToken": "yMDi6uVPJAcphbbz0LaxC07ihWkNTe7m0Xqch8SzfM5Cz3HSIQIDZ65x1f5Qal0jxz0MEyo-_zYcUg", + "checks": { + "passkey": { + "credentialAssertionData": {} + } + } +}' +``` + + + + + diff --git a/docs/docs/guides/integrate/login-ui/password-reset.mdx b/docs/docs/guides/integrate/login-ui/password-reset.mdx new file mode 100644 index 000000000..1d16bcb8b --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/password-reset.mdx @@ -0,0 +1,109 @@ +--- +title: Password Reset/Change +--- + +When your user is on the password screen and has forgotten his password you will probably want him to be able to reset by himself. + +## Flow + +![Register and Login Flow](/img/guides/login-ui/password-reset-flow.png) + +## Request Password Reset + +First you will have to make a request, to ask for a password reset. +The goal is to send the user a verification code, which he can use to verify the password reset request. + +There are two possible ways: You can either let ZITADEL send the notification with the verification code, or you can ask ZITADEL for returning the code and send the email by yourself. + +[Request Password Reset Documentation](/apis/resources/user_service/user-service-password-reset) + +### ZITADEL sends the verification message + +When you want ZITADEL to send the verification code you can define the notification channel. +Per default the verification code will be sent to the email address of the user. + +Make sure to also include the URL Template to customize the reset link in the email sent to the user. + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/password_reset \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "sendLink": { + "notificationType": "NOTIFICATION_TYPE_Email", + "urlTemplate": "https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}" + } + }' +``` + +### ZITADEL returns the code + +Send the request with asking for the return Code in the body of the request. + +#### Request +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/password_reset \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "returnCode": {} +}' +``` + +#### Response + +You will get the verification code in the response: +```bash +{ + "details": { + "sequence": "625", + "changeDate": "2023-06-27T15:02:10.321773Z", + "resourceOwner": "163840776835432705" + }, + "verificationCode": "IBJMUC" +} +``` + +## Send Verification Code + +The verification code is generated and ZITADEL has sent it with the defined channel (email or sms) to your users. +If you have chosen to get the code back in the response, you should now send the code to your user. + +## Change Password + +The next screen should allow the user to enter the verification code and a new password. +From a user experience perspective it is nice to prefill the verification code, so the user doesn't have to do manually. + +As soon as the user has typed the new password, you can send the change password request. +The change password request allows you to set a new password for the user. + +[Change Password Documentation](/apis/resources/user_service/user-service-set-password) + +:::note +This request can be used in the password reset flow as well as to let your user change the password manually. +In this case it requires additionally the current password instead of the verification code. +::: + + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/password \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "newPassword": { + "password": "Secr3tP4ssw0rd!", + "changeRequired": false + }, + "verificationCode": "48CDAP" +}' +``` \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/username-password.mdx b/docs/docs/guides/integrate/login-ui/username-password.mdx index 393aacaf0..95f68d174 100644 --- a/docs/docs/guides/integrate/login-ui/username-password.mdx +++ b/docs/docs/guides/integrate/login-ui/username-password.mdx @@ -10,7 +10,7 @@ sidebar_label: Username and Password ## Register First, we create a new user with a username and password. In the example below we add a user with profile data, a verified email address, and a password. -[Create User Documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-add-human-user) +[Create User Documentation](/apis/resources/user_service/user-service-add-human-user) ### Request diff --git a/docs/docs/guides/integrate/token-introspection/_introspection-response.mdx b/docs/docs/guides/integrate/token-introspection/_introspection-response.mdx new file mode 100644 index 000000000..f3e7b20f4 --- /dev/null +++ b/docs/docs/guides/integrate/token-introspection/_introspection-response.mdx @@ -0,0 +1,21 @@ +Upon successful introspection, regardless of the token type or introspection method, a response with the boolean `active` is returned, indicating if the provided token is active and if the requesting client is part of the token audience. If `active` is true, further information will be provided: + +| **Property** | **Description** | +| --- | --- | +| `aud` | The audience of the token | +| `client_id` | The client_id of the application the token was issued to | +| `exp` | Time the token expires (as unix time) | +| `iat` | Time the token was issued at (as unix time) | +| `iss` | Issuer of the token | +| `jti` | Unique id of the token | +| `nbf` | Time the token must not be used before (as unix time) | +| `scope` | Space delimited list of scopes granted to the token | +| `token_type` | Type of the inspected token. Value is always Bearer | +| `username` | ZITADEL's login name of the user. Consists of username@primarydomain | + + +Depending on the granted scopes, additional information about the authorized user is provided. + +If the authorization fails, an HTTP 401 with invalid_client will be returned. + +In summary, the introspection endpoint plays a crucial role in validating access tokens, either opaque or JWT, ensuring that they are not revoked. diff --git a/docs/docs/guides/integrate/token-introspection/basic-auth.mdx b/docs/docs/guides/integrate/token-introspection/basic-auth.mdx new file mode 100644 index 000000000..18f730de5 --- /dev/null +++ b/docs/docs/guides/integrate/token-introspection/basic-auth.mdx @@ -0,0 +1,103 @@ +--- +title: Basic authentication +--- + +import IntrospectionResponse from './_introspection-response.mdx'; + +This is a guide on how to secure your API using [Basic Authentication](https://zitadel.com/docs/apis/openidoauth/authn-methods#client-secret-basic). + +## Register the API in ZITADEL + +1. Go to your project and click on the **New** button as shown below. + +Register the API + +2. Give a name to your application (Test API 2 is the name given below) and select type **API**. + +Register the API + +3. Select **Basic** as the authentication method and click **Continue**. + +Register the API + +4. Now review your configuration and click **Create**. + +Register the API + +5. You will now see the API’s **Client ID** and the **Client Secret**. Copy them and click **Close**. + +Register the API + +6. When you click **URLs** on the left, you will see the relevant OIDC URLs. Note down the **issuer** URL, **token_endpoint** and **introspection_endpoint**. + +Register the API + +7. Also note down the **Resource ID** of your project. + +Register the API + +## Token introspection + +With Basic Authentication, you will receive a Client ID and Client Secret for your API. Send your client_id and client_secret as a Basic Auth Header in the following format: + +``` +Authorization: "Basic " + base64( formUrlEncode(client_id) + ":" + formUrlEncode(client_secret) ) + +``` + +The request from the API to the introspection endpoint should be in the following format: + +``` +curl --request POST \ + --url {your_domain}/oauth/v2/introspect \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --header 'Authorization: Basic {your_basic_auth_header}' \ + --data token=VjVxyCZmRmWYqd3_F5db9Pb9mHR5fqzhn... + ``` + +Here's an example of how this is done in Python code: + +``` +def introspect_token(self, token_string): + url = ZITADEL_INTROSPECTION_URL + data = {'token': token_string, 'token_type_hint': 'access_token', 'scope': 'openid'} + auth = HTTPBasicAuth(API_CLIENT_ID, API_CLIENT_SECRET) + resp = requests.post(url, data=data, auth=auth) + resp.raise_for_status() + return resp.json() +``` + +## Introspection response + + + +Follow this [tutorial](https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/api-basic-authentication) to learn how to register an API application using Basic Auth with ZITADEL and test it. + diff --git a/docs/docs/guides/integrate/token-introspection/private-key-jwt.mdx b/docs/docs/guides/integrate/token-introspection/private-key-jwt.mdx new file mode 100644 index 000000000..3c83f7cc1 --- /dev/null +++ b/docs/docs/guides/integrate/token-introspection/private-key-jwt.mdx @@ -0,0 +1,192 @@ +--- +title: JSON Web Token profile +--- + +import IntrospectionResponse from './_introspection-response.mdx'; + +This is a guide on how to secure your API using [JSON Web Token (JWT) profile (recommended)](https://zitadel.com/docs/apis/openidoauth/authn-methods#client-secret-basic). + +## Register the API in ZITADEL and generate private and public keys + +1. Go to your project and click on the **New** button as shown below. + +Register the API + +2. Give a name to your application (Test API is the name given below) and select type **API**. + +Register the API + +3. Select **JWT** as the authentication method and click **Continue**. + +Register the API + +4. Now review your configuration and click **Create**. + +Register the API + +5. You will now see the API’s **Client ID**. You will not see a client secret because we are using a private JWT key. + +Register the API + +6. Next, we must create the key pairs. Click on **New**. + +Register the API + +7. Select **JSON** as the type of key. You can also set an expiration time for the key or leave it empty. Click on **Add**. + +Register the API + +8. Download the created key by clicking the **Download** button and then click **Close**. + +Register the API + +9. The key will be downloaded. + +Register the API + +10. When you click on URLs on the left, you will see the relevant OIDC URLs. Note down the **issuer** URL, **token_endpoint** and **introspection_endpoint**. + +Register the API + +11. The key that you downloaded will be of the following format. +``` +{ + "type":"application", + "keyId":"", + "key":"-----BEGIN RSA PRIVATE KEY-----\\n-----END RSA PRIVATE KEY-----\n", + "appId":"", + "clientId":"" +} +``` +12. Also note down the **Resource ID** of your project. + +Register the API + +## Token introspection + +You must send a client_assertion as a JWT signed with the API’s private key for ZITADEL to validate the signature against the registered public key. + +Request parameters​: + +| **Parameter** | **Description** | +---|--- +| `client_assertion` | When using JWT profile for token or introspection endpoints, you must provide a JWT as an assertion generated with the structure shown below and signed with the downloaded key. | +| `client_assertion_type` | `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` | + + +You must create your client assertion JWT with the following format: + +Header: +```json +{ + "alg": "RS256", + "kid": "81693565968962154" (keyId from your key file) +} +``` + + +Payload: +```json +{ + "iss": "78366401571920522@acme", (clientId from your key file) + "sub": "78366401571920522@acme", (clientId from your key file) + "aud": "https://{your_domain}", (your ZITADEL domain/issuer URL) + "exp": 1605183582, (Unix timestamp of the expiry) + "iat": 1605179982 (Unix timestamp of the creation signing time of the JWT, MUST NOT be older than 1h) +} +``` + +Create the JSON Web Token with the above header and payload, and sign it with the private key in your key file. You can do this programmatically or use tools like [https://github.com/zitadel/zitadel-tools](https://github.com/zitadel/zitadel-tools) and [https://dinochiesa.github.io/jwt/](https://dinochiesa.github.io/jwt/). + +The request from the API to the introspection endpoint should be in the following format: +```bash +curl --request POST \ + --url {your_domain}/oauth/v2/introspect \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \ + --data client_assertion=eyJhbGciOiJSUzI1Ni... \ + --data token=VjVxyCZmRmWYqd3_F5db9Pb9mHR + ``` + +Here's an example of how this is done in Python code: + +```python +def introspect_token(self, token_string): + #Create JWT for client assertion + payload = { + "iss": API_PRIVATE_KEY_FILE["client_id"], + "sub": API_PRIVATE_KEY_FILE["client_id"], + "aud": ZITADEL_DOMAIN, + "exp": int(time.time()) + 60 * 60, # Expires in 1 hour + "iat": int(time.time()) + } + headers = { + "alg": "RS256", + "kid": API_PRIVATE_KEY_FILE["key_id"] + } + jwt_token = jwt.encode(payload, API_PRIVATE_KEY_FILE["private_key"], algorithm="RS256", headers=headers) + + #Send introspection request + headers = {"Content-Type": "application/x-www-form-urlencoded"} + data = { + "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + "client_assertion": jwt_token, + "token": token_string + } + response = requests.post(ZITADEL_INTROSPECTION_URL, headers=headers, data=data) + response.raise_for_status() + token_data = response.json() + print(f"Token data from introspection: {token_data}") + return token_data + +``` +## Introspection response + + + +Follow this [tutorial](https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/api-jwt) to learn how to register an API application using JWT Profile with ZITADEL and test it. + diff --git a/docs/docs/guides/manage/console/instance-settings.mdx b/docs/docs/guides/manage/console/instance-settings.mdx index 584d095a5..2603caee5 100644 --- a/docs/docs/guides/manage/console/instance-settings.mdx +++ b/docs/docs/guides/manage/console/instance-settings.mdx @@ -125,6 +125,7 @@ Secondfactors (2FA): Force a user to register and use a multifactor authentication, by checking the option "Force MFA". Ensure that you have added the MFA methods you want to allow. +Or you can enable the "Force MFA for local authenticated users", which will enforce this rule only on local authentication, but not on users authenticated through an Identity Provider. ### Login Lifetimes diff --git a/docs/docs/guides/manage/console/projects.mdx b/docs/docs/guides/manage/console/projects.mdx index 2acf0df86..411674c18 100644 --- a/docs/docs/guides/manage/console/projects.mdx +++ b/docs/docs/guides/manage/console/projects.mdx @@ -19,7 +19,11 @@ You would have to create roles for administration and your clients in this very To create a project, navigate to your organization, then projects or directly via , and then click the button to create a new project. -Empty Project +Empty Project then enter your project name and continue. @@ -51,7 +55,7 @@ Organizations can then create authorizations for their users on their own. The p Grants -2. Enter the domain of the organization you want to grant (go to the organization detail page if you can't remember it), hit the search button and continue. +2. Search the organization you want to grant using the auto complete input and continue. 3. Select some roles you would like to grant to the organization and confirm. 4. You should now see the granted organization in the section **grants**. diff --git a/docs/docs/guides/manage/customize/texts.md b/docs/docs/guides/manage/customize/texts.md index 64741a3ef..e64a3eaca 100644 --- a/docs/docs/guides/manage/customize/texts.md +++ b/docs/docs/guides/manage/customize/texts.md @@ -43,6 +43,8 @@ ZITADEL is available in the following languages - Polish(pl) - 简体中文(zh) - Bulgarian (bg) +- Portuguese (pt) +- Macedonian (mk) A language is displayed based on your agent's language header. The default language is English. diff --git a/docs/docs/guides/solution-scenarios/frontend-calling-backend-API.mdx b/docs/docs/guides/solution-scenarios/frontend-calling-backend-API.mdx new file mode 100644 index 000000000..a74c29e6c --- /dev/null +++ b/docs/docs/guides/solution-scenarios/frontend-calling-backend-API.mdx @@ -0,0 +1,65 @@ +--- +title: Frontend and API communication +--- + +This guide contains a use case and ZITADEL integration. + +In a typical web application architecture, the front-end and back-end communicate to exchange data and provide functionality to users. Let's consider a use case where a front-end application needs to communicate with a back-end API using secure authentication and authorization. Let’s explore how ZITADEL can be used to add front-end login and facilitate this communication. + +Single-Page Applications (SPAs) are web applications that run entirely in the browser, without a back-end server. In ZITADEL SPAs should use the Authorization Code Grant with PKCE or the Implicit Grant (if PKCE is not feasible) to obtain an access token. + +While APIs are vital for communication between applications and services, they don't directly participate in user authentication. Instead, they often authorize client requests based on access tokens issued by an authorization server. APIs in ZITADEL use grant types like JWT Profile or Basic Authentication to access the authorization server's introspection endpoint for token validation. + +## A real-world scenario + +Suppose there is a news portal web app that allows users to browse through various news articles and personalize their news feed based on their preferences. The back-end API handles fetching and delivering news content from the database. + +**Front-End Login**: A user visits the news portal and opts to log in for a personalized news feed. They are redirected to the Identity Provider’s (IdP) login page, where they authenticate with their credentials. Upon successful authentication, the IdP issues access and ID tokens to the front-end app. + +** Back-End API Communication**: When the user browses through the news feed, the front-end app makes an API request to the back-end, including the access token in the Authorization header. The back-end API, upon receiving the request, uses the IdP’s introspection endpoint to validate the access token. Once validated, it fetches personalized news data based on the user's preferences from the news database. + +While it is true that the back-end API typically needs to authenticate with the IdP, in this specific use case, the back-end API can work with a client credential / JWT since it's not a public client. This means that instead of relying on user-specific authentication, the back-end API can obtain a client credential (such as a client ID and client secret) from the IdP to authenticate itself and validate the access token received from the front-end app. This approach ensures secure communication between the front-end app, the back-end API, and the IdP, while still allowing the back-end API to access user-specific data and provide personalized news feeds. + +## A simplified example with a React frontend and a Python Flask API + +In this example, the application is a web-based quote generator that employs a secure user authentication system via ZITADEL. The functionality of the app is outlined below: + +1. Upon starting, the application provides a login button +2. The user is then redirected to ZITADEL's login page to enter their credentials. +3. Once the login is successful, the application then greets the user by extracting the user's name, thus providing a personalized experience. +4. The application presents an option for the user to generate a quote via a button. Upon pressing this button, the front-end application communicates with the back-end API using the user's access token received from ZITADEL. +5. The back-end API introspects the access token for validity using ZITADEL's introspection endpoint. If the token is valid, the API generates a quote and sends it as a response to the front-end application, which is then displayed to the user in their browser. + +## Setting up the applications and ZITADEL + + +All code and instructions to run the sample application can be found at [https://github.com/zitadel/example-quote-generator-app/](https://github.com/zitadel/example-quote-generator-app/). You can also find the steps for the integration between the front-end, back-end API, and ZITADEL in the README.md. + +You can create the front-end application (User Agent) and the API in the same project or in a different project. In this example, we have created both in one. Configure the applications with appropriate settings (as instructed). + +User Agent and API applications in a single project + + +### Front-end login with ZITADEL + +- You must create a User Agent application in your project to add login to your React application using the Authorization Code with PKCE flow. This allows the front-end application to integrate with ZITADEL to enable user authentication and authorization. +- In the React front-end application, configure the ZITADEL OIDC client settings, including the client ID, ZITADEL URLs, redirect URIs, and required scopes. +- Implement the login flow, authentication callbacks, and token handling logic in the front-end application. +- When a user visits the front-end application, they are presented with a login option. +- Upon clicking the login button, the frontend initiates the Authorization Code with PKCE authentication flow and redirects the user to the ZITADEL login page. The user enters their credentials and authenticates with ZITADEL. Authorization Code Flow returns an authorization code to the client application, which can then exchange it for an ID token and an access token directly. This provides the benefit of not exposing any tokens to the user agent and possibly other malicious applications with access to the user agent. +- You must set up the required scopes and claims to ensure the front-end and back-end can exchange data securely. It’s important to note that when specifying the scope when calling the token API, the scope must contain the project ID of the ZITADEL project in which the API resides (to enable token validation by the back-end API):`scope:'openid profile email urn:zitadel:iam:org:project:id::aud'` +- Also, we want to include user info inside the token to avoid calling the user info endpoint, so go to Token Settings in the front-end app and select User Info inside ID Token. +- After a successful authentication, ZITADEL generates an access token and an ID token. +- The front-end application receives these tokens and stores them securely (e.g., in browser storage). + +### Token exchange and user information + +- Once the frontend obtains the tokens, it can extract certain information from the ID token itself (e.g., user ID, email, etc.) without making an additional request. +- If more user information is required, the frontend can use the access token to call the ZITADEL User Info endpoint. This endpoint provides additional user details, such as name, profile picture, etc. + +### Back-end API communication + +- To communicate with the back-end API, the front-end includes the access token in the Authorization header of API requests. +- The back-end API receives the request and needs to validate and authorize the token before processing the request. +- The API performs token introspection using ZITADEL's introspection endpoint to validate the access token. This API uses Basic Authentication to invoke the [introspection endpoint](/docs/apis/openidoauth/endpoints#introspection_endpoint), which means it sends its client ID and client secret along with the access token received. +- If the token is valid and active, the API proceeds to handle the requested action or fetch data from the underlying data sources. diff --git a/docs/docs/legal/_piid-table.mdx b/docs/docs/legal/_piid-table.mdx index 6677201b3..4fc3c3618 100644 --- a/docs/docs/legal/_piid-table.mdx +++ b/docs/docs/legal/_piid-table.mdx @@ -8,7 +8,7 @@ Basic data
    -
  • Surname and first name
  • +
  • Family and given name
  • Email addresses
  • User name
diff --git a/docs/docs/legal/privacy-policy.mdx b/docs/docs/legal/privacy-policy.mdx index 91b713834..e922117e9 100644 --- a/docs/docs/legal/privacy-policy.mdx +++ b/docs/docs/legal/privacy-policy.mdx @@ -21,7 +21,7 @@ Switzerland Our representative in the EU is -**VGS Datenschutzpartner UG** +**VGS Datenschutzpartner GmbH** Am Kaiserkai 69 20457 Hamburg Germany diff --git a/docs/docs/self-hosting/deploy/compose.mdx b/docs/docs/self-hosting/deploy/compose.mdx index 563cdf946..57edf063c 100644 --- a/docs/docs/self-hosting/deploy/compose.mdx +++ b/docs/docs/self-hosting/deploy/compose.mdx @@ -8,6 +8,8 @@ import DockerComposeSaSource from '!!raw-loader!./docker-compose-sa.yaml' import Disclaimer from './_disclaimer.mdx' import DefaultUser from './_defaultuser.mdx' import Next from './_next.mdx' +import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx'; + The setup is tested against Docker version 20.10.17 and Docker Compose version v2.2.3 @@ -29,6 +31,8 @@ docker compose up --detach + + ## VideoGuide diff --git a/docs/docs/self-hosting/deploy/knative.mdx b/docs/docs/self-hosting/deploy/knative.mdx index 54f22ab17..e2a67ccb6 100644 --- a/docs/docs/self-hosting/deploy/knative.mdx +++ b/docs/docs/self-hosting/deploy/knative.mdx @@ -5,6 +5,8 @@ title: Knative import Disclaimer from './_disclaimer.mdx' import DefaultUser from './_defaultuser.mdx' import Next from './_next.mdx' +import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx'; + ## Install Knative @@ -31,7 +33,7 @@ kn service create zitadel \ --env ZITADEL_EXTERNALPORT=80 \ --env ZITADEL_TLS_ENABLED=false \ --env ZITADEL_EXTERNALDOMAIN=zitadel.default.127.0.0.1.sslip.io \ ---arg "start-from-init" --arg "--masterkey" --arg "MasterkeyNeedsToHave32Characters" +--arg "start-from-init" --arg "--masterkey" --arg "MasterkeyNeedsToHave32Characters" ``` ### Knavite yaml @@ -59,6 +61,8 @@ If you didn't configure something else, this is the default IAM admin users logi * username: zitadel-admin@zitadel.zitadel.default.127.0.0.1.sslip.io * password: Password1! + + ## VideoGuide diff --git a/docs/docs/self-hosting/deploy/kubernetes.mdx b/docs/docs/self-hosting/deploy/kubernetes.mdx index fa214d577..bca072326 100644 --- a/docs/docs/self-hosting/deploy/kubernetes.mdx +++ b/docs/docs/self-hosting/deploy/kubernetes.mdx @@ -5,6 +5,8 @@ title: Kubernetes import Disclaimer from './_disclaimer.mdx' import DefaultUser from './_defaultuser.mdx' import Next from './_next.mdx' +import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx'; + Installation and configuration details are described in the [open source ZITADEL charts repo](https://github.com/zitadel/zitadel-charts). By default, the chart installs a secure and highly available ZITADEL instance. @@ -46,6 +48,8 @@ kubectl port-forward svc/my-zitadel 8080 + + ## Setup ZITADEL and a Service Account Admin With this setup, you don't create a human user that has the IAM_OWNER role. diff --git a/docs/docs/self-hosting/deploy/linux.mdx b/docs/docs/self-hosting/deploy/linux.mdx index c1b959793..a6ed2e43c 100644 --- a/docs/docs/self-hosting/deploy/linux.mdx +++ b/docs/docs/self-hosting/deploy/linux.mdx @@ -5,6 +5,8 @@ title: Linux import Disclaimer from './_disclaimer.mdx' import DefaultUser from './_defaultuser.mdx' import Next from './_next.mdx' +import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx'; + ## Install CockroachDB @@ -38,6 +40,8 @@ ZITADEL_EXTERNALSECURE=false zitadel start-from-init --masterkey "MasterkeyNeeds + + ## VideoGuide @@ -54,3 +58,5 @@ This key can be used to provision resources with for example [Terraform](/docs/g + + diff --git a/docs/docs/self-hosting/deploy/loadbalancing-example/example-traefik.yaml b/docs/docs/self-hosting/deploy/loadbalancing-example/example-traefik.yaml index 4b4f5a35c..c16f74a46 100644 --- a/docs/docs/self-hosting/deploy/loadbalancing-example/example-traefik.yaml +++ b/docs/docs/self-hosting/deploy/loadbalancing-example/example-traefik.yaml @@ -21,7 +21,6 @@ providers: filename: /etc/traefik/traefik.yaml http: - middlewares: zitadel: headers: @@ -29,7 +28,7 @@ http: allowedHosts: - 'my.domain' customRequestHeaders: - :authority: 'my.domain' + authority: 'my.domain' redirect-to-https: redirectScheme: scheme: https diff --git a/docs/docs/self-hosting/deploy/loadbalancing-example/loadbalancing-example.mdx b/docs/docs/self-hosting/deploy/loadbalancing-example/loadbalancing-example.mdx index e4a668b0f..9f49d1f5c 100644 --- a/docs/docs/self-hosting/deploy/loadbalancing-example/loadbalancing-example.mdx +++ b/docs/docs/self-hosting/deploy/loadbalancing-example/loadbalancing-example.mdx @@ -8,6 +8,7 @@ import ExampleTraefikSource from '!!raw-loader!./example-traefik.yaml' import ExampleZITADELConfigSource from '!!raw-loader!./example-zitadel-config.yaml' import ExampleZITADELSecretsSource from '!!raw-loader!./example-zitadel-secrets.yaml' import ExampleZITADELInitStepsSource from '!!raw-loader!./example-zitadel-init-steps.yaml' +import NoteInstanceNotFound from '../troubleshooting/_note_instance_not_found.mdx'; With this example configuration, you create a near production environment for ZITADEL with [Docker Compose](https://docs.docker.com/compose/). @@ -61,7 +62,7 @@ export ZITADEL_MASTERKEY="$(tr -dc A-Za-z0-9 + ## Troubleshooting You can connect to cockroach like this: `docker exec -it loadbalancing-example-my-cockroach-db-1 cockroach sql --host my-cockroach-db --certs-dir /cockroach/certs/` diff --git a/docs/docs/self-hosting/deploy/macos.mdx b/docs/docs/self-hosting/deploy/macos.mdx index f00bdd393..53719ef99 100644 --- a/docs/docs/self-hosting/deploy/macos.mdx +++ b/docs/docs/self-hosting/deploy/macos.mdx @@ -5,6 +5,7 @@ title: MacOS import Disclaimer from './_disclaimer.mdx' import DefaultUser from './_defaultuser.mdx' import Next from './_next.mdx' +import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx'; ## Install CockroachDB @@ -44,6 +45,7 @@ ZITADEL_EXTERNALSECURE=false zitadel start-from-init --masterkey "MasterkeyNeeds ``` + ## VideoGuide diff --git a/docs/docs/self-hosting/deploy/troubleshooting/_instance_not_found.mdx b/docs/docs/self-hosting/deploy/troubleshooting/_instance_not_found.mdx new file mode 100644 index 000000000..98785275b --- /dev/null +++ b/docs/docs/self-hosting/deploy/troubleshooting/_instance_not_found.mdx @@ -0,0 +1,5 @@ +`ID=QUERY-n0wng Message=Instance not found` + +If you're self hosting with a custom domain, you need to instruct ZITADEL to use the `ExternalDomain`. +You can find further instructions in our guide about [custom domains](https://zitadel.com/docs/self-hosting/manage/custom-domain). +We also provide a guide on how to [configure](https://zitadel.com/docs/self-hosting/manage/configure) ZITADEL with variables from files or environment variables. diff --git a/docs/docs/self-hosting/deploy/troubleshooting/_note_instance_not_found.mdx b/docs/docs/self-hosting/deploy/troubleshooting/_note_instance_not_found.mdx new file mode 100644 index 000000000..c194800e6 --- /dev/null +++ b/docs/docs/self-hosting/deploy/troubleshooting/_note_instance_not_found.mdx @@ -0,0 +1,5 @@ +:::note +This guide is based on a local setup. +If you encounter an error "Instance Not Found" please read the following section: +[Instance not found](/docs/self-hosting/deploy/troubleshooting#instance-not-found) +::: \ No newline at end of file diff --git a/docs/docs/self-hosting/deploy/troubleshooting/troubleshooting.mdx b/docs/docs/self-hosting/deploy/troubleshooting/troubleshooting.mdx new file mode 100644 index 000000000..aa5b2ed2e --- /dev/null +++ b/docs/docs/self-hosting/deploy/troubleshooting/troubleshooting.mdx @@ -0,0 +1,10 @@ +--- +title: Troubleshoot +--- + +import InstanceNotFound from '/docs/self-hosting/deploy/troubleshooting/_instance_not_found.mdx'; + +## Instance not found + + + \ No newline at end of file diff --git a/docs/docs/self-hosting/manage/production.md b/docs/docs/self-hosting/manage/production.md index 0f3169fa0..f00e7fe0e 100644 --- a/docs/docs/self-hosting/manage/production.md +++ b/docs/docs/self-hosting/manage/production.md @@ -61,6 +61,26 @@ Instead, your execution environment should provide tooling for managing logs in This includes tasks like rotating files, routing, collecting, archiving and cleaning-up. For example, systemd has journald and kubernetes has fluentd and fluentbit. +## Telemetry + +If you want to have some data about reached usage milestones pushed to external systems, enable telemetry in the ZITADEL configuration. + +The following table describes the milestones that are sent to the endpoints: + +| Trigger | Description | +|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| A virtual instance is created. | This data point is also sent when the first instance is automatically created during the ZITADEL binaries setup phase in a self-hosting scenario. | +| An authentication succeeded for the first time on an instance. | This is the first authentication with the instances automatically created admin user during the instance setup, which can be a human or a machine. | +| A project is created for the first time in a virtual instance. | The ZITADEL project that is automatically created during the instance setup is omitted. | +| An application is created for the first time in a virtual instance. | The applications in the ZITADEL project that are automatically created during the instance setup are omitted. | +| An authentication succeeded for the first time in a virtal instances application. | This is the first authentication using a ZITADEL application that is not created during the instance setup phase. | +| A virtual instance is deleted. | This data point is sent when a virtual instance is deleted via ZITADELs system API | + + +ZITADEL pushes the metrics by projecting certain events. +Therefore, you can configure delivery guarantees not in the Telemetry section of the ZITADEL configuration, +but in the Projections.Customizations.Telemetry section + ## Database ### Prefer CockroachDB diff --git a/docs/docs/self-hosting/manage/tls_modes.mdx b/docs/docs/self-hosting/manage/tls_modes.mdx index bb67ee90f..dc34dca07 100644 --- a/docs/docs/self-hosting/manage/tls_modes.mdx +++ b/docs/docs/self-hosting/manage/tls_modes.mdx @@ -2,8 +2,8 @@ title: TLS Modes --- -To allow ZITADEL to be run on any kind of infrastrucute it allows to configure on how tho handle TLS connections. -There are three mode of operation: `external`, `enabled`, `disabled`. +To allow ZITADEL to be run on any kind of infrastructure it allows to configure on how tho handle TLS connections. +There are three mode of operation: `external`, `enabled`, `disabled`. Generally this command is set as argument while starting ZITADEL. For example like this: @@ -11,18 +11,18 @@ Generally this command is set as argument while starting ZITADEL. For example li zitadel start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled ``` -## External +## External The mode `external` allows you to configure ZITADEL in such a way that it will instruct its clients to use https. However ZITADEL delegates the management of TLS connections to a reverseproxy, web application firewall or a service mesh. ## Enabled -When using the mode `enabled` ZITADEL is setup to await incoming connections in an encrypted fashion. +When using the mode `enabled` ZITADEL is setup to await incoming connections in an encrypted fashion. Wether it is from a client directly, a reverseproxy or web application firewall. This allows http connections to be secured at the transport level the whole way. -If you use the mode `enabled` you need to configure ZITADEL with the nessecary TLS settings. +If you use the mode `enabled` you need to configure ZITADEL with the necessary TLS settings. ```yaml TLS: @@ -31,17 +31,17 @@ TLS: # either directly or by a path to the corresponding file Enabled: true # Path to the private key of the TLS certificate, it will be loaded into the Key - # and overwrite any exising value + # and overwrite any existing value KeyPath: #/path/to/key/file.pem # Private key of the TLS certificate (KeyPath will this overwrite, if specified) Key: # # Path to the certificate for the TLS connection, it will be loaded into the Cert - # and overwrite any exising value + # and overwrite any existing value CertPath: #/path/to/cert/file.pem # Certificate for the TLS connection (CertPath will this overwrite, if specified) Cert: # ``` - + ## Disabled With the mode `disabled` ZITADEL is instructed to await all connections with plain http without TLS. @@ -55,4 +55,4 @@ Be aware this is not a secure setup and should only be used for test systems! ## HTTP/2 To allow ZITADEL to function properly please make sure that HTTP/2 is enabled. If you are using the mode `external` or `disabled` make sure to verify h2c compatibilty. -You can read more about how ZITADEL utilizes in our [HTTP/2 docs](/self-hosting/manage/http2). \ No newline at end of file +You can read more about how ZITADEL utilizes in our [HTTP/2 docs](/self-hosting/manage/http2). diff --git a/docs/docs/support/troubleshooting.md b/docs/docs/support/troubleshooting.mdx similarity index 91% rename from docs/docs/support/troubleshooting.md rename to docs/docs/support/troubleshooting.mdx index 8027152c3..76d320463 100644 --- a/docs/docs/support/troubleshooting.md +++ b/docs/docs/support/troubleshooting.mdx @@ -29,14 +29,6 @@ To make sure, that your new settings will trigger, please restart your mobile ph Do you still face this issue? Please contact us, and we will help you find out what the problem is. -## Instance not found - -`ID=QUERY-n0wng Message=Instance not found` - -If you're self hosting with a custom domain, you need to instruct ZITADEL to use the `ExternalDomain`. -You can find further instructions in our guide about [custom domains](https://zitadel.com/docs/self-hosting/manage/custom-domain). -We also provide a guide on how to [configure](https://zitadel.com/docs/self-hosting/manage/configure) ZITADEL with variables from files or environment variables. - ## Invalid audience `invalid audience (APP-Zxfako)` diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index ccac55b08..c7131a226 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -274,6 +274,13 @@ module.exports = { groupPathsBy: "tag", }, }, + oidc: { + specPath: ".artifacts/openapi/zitadel/oidc/v2alpha/oidc_service.swagger.json", + outputDir: "docs/apis/resources/oidc_service", + sidebarOptions: { + groupPathsBy: "tag", + }, + }, settings: { specPath: ".artifacts/openapi/zitadel/settings/v2alpha/settings_service.swagger.json", outputDir: "docs/apis/resources/settings_service", diff --git a/docs/sidebars.js b/docs/sidebars.js index 755a57085..a90e7a0ad 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -150,6 +150,22 @@ module.exports = { "guides/integrate/logout", ], }, + { + type: "category", + label: "Token introspection", + link: { + type: "generated-index", + title: "Token introspection", + slug: "/guides/integrate/token-introspection", + description: + "Token introspection is the process of checking whether an access token is valid and can be used to access protected resources. You have an API that acts as an OAuth resource server and can be accessed by user-facing applications. To validate an access token by calling the ZITADEL introspection API, you can use the JSON Web Token (JWT) Profile (recommended) or Basic Authentication for token introspection. It's crucial to understand that the API is entirely separate from the front end. The API shouldn’t concern itself with the token type received. Instead, it's about how the API chooses to call the introspection endpoint, either through JWT Profile or Basic Authentication. Many APIs assume they might receive a JWT and attempt to verify it based on signature or expiration. However, with ZITADEL, you can send either a JWT or an opaque Bearer token from the client end to the API. This flexibility is one of ZITADEL's standout features.", + }, + collapsed: true, + items: [ + "guides/integrate/token-introspection/private-key-jwt", + "guides/integrate/token-introspection/basic-auth", + ], + }, { type: "category", label: "Authenticate service users", @@ -169,20 +185,23 @@ module.exports = { }, { type: "category", - label: "Build your own Login-UI", + label: "Build your own login UI", link: { type: "generated-index", - title: "Build your own Login-UI", + title: "Build your own login UI", slug: "/guides/integrate/login-ui", description: - "In the following guides you will learn how to create your own login ui with our APIs. The different scenarios like username/password, external identity provider, etc will be shown.", + "In the following guides you will learn how to create your own login UI with our APIs. The different scenarios like username/password, external identity provider, etc. will be shown." }, collapsed: true, items: [ "guides/integrate/login-ui/username-password", "guides/integrate/login-ui/external-login", + "guides/integrate/login-ui/passkey", + "guides/integrate/login-ui/mfa", "guides/integrate/login-ui/select-account", + "guides/integrate/login-ui/password-reset", "guides/integrate/login-ui/logout", "guides/integrate/login-ui/oidc-standard" ], @@ -206,6 +225,7 @@ module.exports = { "guides/integrate/identity-providers/gitlab", "guides/integrate/identity-providers/ldap", "guides/integrate/identity-providers/openldap", + "guides/integrate/identity-providers/migrate", "guides/integrate/identity-providers/google-oidc", "guides/integrate/identity-providers/azuread-oidc", ], @@ -293,6 +313,7 @@ module.exports = { "guides/solution-scenarios/saas", "guides/solution-scenarios/domain-discovery", "guides/solution-scenarios/configurations", + "guides/solution-scenarios/frontend-calling-backend-API", ], }, { @@ -464,6 +485,20 @@ module.exports = { }, items: require("./docs/apis/resources/session_service/sidebar.js"), }, + { + type: "category", + label: "OIDC lifecycle (Alpha)", + link: { + type: "generated-index", + title: "OIDC service API (Alpha)", + slug: "/apis/resources/oidc_service", + description: + "Get OIDC Auth Request details and create callback URLs.\n"+ + "\n"+ + "This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.", + }, + items: require("./docs/apis/resources/oidc_service/sidebar.js"), + }, { type: "category", label: "Settings lifecycle (alpha)", @@ -554,7 +589,8 @@ module.exports = { "self-hosting/deploy/compose", "self-hosting/deploy/knative", "self-hosting/deploy/kubernetes", - "self-hosting/deploy/loadbalancing-example/loadbalancing-example" + "self-hosting/deploy/loadbalancing-example/loadbalancing-example", + "self-hosting/deploy/troubleshooting/troubleshooting" ], }, { diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-1.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-1.png new file mode 100644 index 000000000..38c25a4b1 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-1.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-2.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-2.png new file mode 100644 index 000000000..6915f4b8f Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-2.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-3.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-3.png new file mode 100644 index 000000000..a0a18f206 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-3.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-4.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-4.png new file mode 100644 index 000000000..ac3fa06d2 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-4.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-5.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-5.png new file mode 100644 index 000000000..a6dbe546a Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-5.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-6.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-6.png new file mode 100644 index 000000000..05c58384b Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-6.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-basic-auth-7.png b/docs/static/img/guides/integrate/token-introspection-basic-auth-7.png new file mode 100644 index 000000000..c3b984383 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-basic-auth-7.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-1.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-1.png new file mode 100644 index 000000000..1025eb869 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-1.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-10.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-10.png new file mode 100644 index 000000000..05c58384b Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-10.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-11.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-11.png new file mode 100644 index 000000000..c3b984383 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-11.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-2.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-2.png new file mode 100644 index 000000000..1bb592763 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-2.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-3.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-3.png new file mode 100644 index 000000000..d4deeb6e9 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-3.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-4.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-4.png new file mode 100644 index 000000000..7063c251e Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-4.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-5.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-5.png new file mode 100644 index 000000000..9f5bddb7d Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-5.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-6.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-6.png new file mode 100644 index 000000000..d213eaee9 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-6.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-7.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-7.png new file mode 100644 index 000000000..d783c92cd Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-7.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-8.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-8.png new file mode 100644 index 000000000..47299c092 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-8.png differ diff --git a/docs/static/img/guides/integrate/token-introspection-jwt-profile-9.png b/docs/static/img/guides/integrate/token-introspection-jwt-profile-9.png new file mode 100644 index 000000000..e20a66449 Binary files /dev/null and b/docs/static/img/guides/integrate/token-introspection-jwt-profile-9.png differ diff --git a/docs/static/img/guides/login-ui/passkey-login-flow.png b/docs/static/img/guides/login-ui/passkey-login-flow.png new file mode 100644 index 000000000..638b58d6d Binary files /dev/null and b/docs/static/img/guides/login-ui/passkey-login-flow.png differ diff --git a/docs/static/img/guides/login-ui/passkey-registration-flow.png b/docs/static/img/guides/login-ui/passkey-registration-flow.png new file mode 100644 index 000000000..9dc1a47fc Binary files /dev/null and b/docs/static/img/guides/login-ui/passkey-registration-flow.png differ diff --git a/docs/static/img/guides/login-ui/password-reset-flow.png b/docs/static/img/guides/login-ui/password-reset-flow.png new file mode 100644 index 000000000..56e7f8eff Binary files /dev/null and b/docs/static/img/guides/login-ui/password-reset-flow.png differ diff --git a/docs/static/img/guides/login-ui/register-totp-flow.png b/docs/static/img/guides/login-ui/register-totp-flow.png new file mode 100644 index 000000000..75a4da5c1 Binary files /dev/null and b/docs/static/img/guides/login-ui/register-totp-flow.png differ diff --git a/docs/static/img/guides/login-ui/register-u2f-flow.png b/docs/static/img/guides/login-ui/register-u2f-flow.png new file mode 100644 index 000000000..2e1c39d02 Binary files /dev/null and b/docs/static/img/guides/login-ui/register-u2f-flow.png differ diff --git a/docs/static/img/guides/solution-scenarios/frontend-calling-backend-API_1.png b/docs/static/img/guides/solution-scenarios/frontend-calling-backend-API_1.png new file mode 100644 index 000000000..14577545a Binary files /dev/null and b/docs/static/img/guides/solution-scenarios/frontend-calling-backend-API_1.png differ diff --git a/docs/vercel.json b/docs/vercel.json index 9a977c840..a42f8c252 100644 --- a/docs/vercel.json +++ b/docs/vercel.json @@ -3,7 +3,7 @@ "rewrites": [ { "source": "/docs/proxy/js/script.js", - "destination": "https://plausible.io/js/script.tagged-events.outbound-links.js" + "destination": "https://plausible.io/js/script.tagged-events.pageview-props.outbound-links.js" }, { "source": "/docs/proxy/api/event", @@ -15,6 +15,10 @@ } ], "redirects": [ - { "source": "/", "destination": "/docs" } + { "source": "/", "destination": "/docs" }, + { "source": "/docs/apis/mgmt/:slug*", "destination": "/docs/apis/resources/mgmt/:slug*", "permanent": true }, + { "source": "/docs/apis/auth/:slug*", "destination": "/docs/apis/resources/auth/:slug*", "permanent": true }, + { "source": "/docs/apis/system/:slug*", "destination": "/docs/apis/resources/system/:slug*", "permanent": true }, + { "source": "/docs/apis/admin/:slug*", "destination": "/docs/apis/resources/admin/:slug*", "permanent": true } ] } diff --git a/e2e/config/host.docker.internal/docker-compose.yaml b/e2e/config/host.docker.internal/docker-compose.yaml index dbedbeee9..0bcac1a93 100644 --- a/e2e/config/host.docker.internal/docker-compose.yaml +++ b/e2e/config/host.docker.internal/docker-compose.yaml @@ -1,18 +1,22 @@ version: '3.8' services: - zitadel: - extends: - file: '../localhost/docker-compose.yaml' - service: 'zitadel' - volumes: - - ./zitadel.yaml:/zitadel.yaml db: extends: file: '../localhost/docker-compose.yaml' service: 'db' + zitadel: + depends_on: + db: + condition: 'service_healthy' + extends: + file: '../localhost/docker-compose.yaml' + service: 'zitadel' + volumes: + - ./zitadel.yaml:/zitadel.yaml + prepare: image: node:18-alpine3.15 working_dir: /e2e diff --git a/e2e/cypress/e2e/projects/projects.cy.ts b/e2e/cypress/e2e/projects/projects.cy.ts index 36768a153..101608289 100644 --- a/e2e/cypress/e2e/projects/projects.cy.ts +++ b/e2e/cypress/e2e/projects/projects.cy.ts @@ -1,19 +1,23 @@ import { Context } from 'support/commands'; import { ensureProjectDoesntExist, ensureProjectExists } from '../../support/api/projects'; +import { ensureOrgExists } from 'support/api/orgs'; describe('projects', () => { beforeEach(() => { cy.context().as('ctx'); }); + const defaultOrg = 'e2eorgnewdefault'; const testProjectNameCreate = 'e2eprojectcreate'; const testProjectNameDelete = 'e2eprojectdelete'; describe('add project', () => { beforeEach(`ensure it doesn't exist already`, () => { cy.get('@ctx').then((ctx) => { - ensureProjectDoesntExist(ctx.api, testProjectNameCreate); - cy.visit(`/projects`); + ensureOrgExists(ctx, defaultOrg).then(() => { + ensureProjectDoesntExist(ctx.api, testProjectNameCreate); + cy.visit(`/projects`); + }); }); }); @@ -27,10 +31,49 @@ describe('projects', () => { it('should configure a project to assert roles on authentication'); }); + describe('create project grant', () => { + const testRoleName = 'e2eroleundertestname'; + + beforeEach('ensure it exists', () => { + cy.get('@ctx').then((ctx) => { + ensureProjectExists(ctx.api, testProjectNameCreate).as('projectId'); + cy.get('@projectId').then((projectId) => { + cy.visit(`/projects/${projectId}`); + }); + }); + }); + + it('should add a role', () => { + cy.get('[data-e2e="sidenav-element-roles"]').click(); + cy.get('[data-e2e="add-new-role"]').click(); + cy.get('[formcontrolname="key"]').type(testRoleName); + cy.get('[formcontrolname="displayName"]').type('e2eroleundertestdisplay'); + cy.get('[formcontrolname="group"]').type('e2eroleundertestgroup'); + cy.get('[data-e2e="save-button"]').click(); + cy.shouldConfirmSuccess(); + cy.contains('tr', testRoleName); + }); + + it('should add a project grant', () => { + const rowSelector = `tr:contains(${testRoleName})`; + + cy.get('[data-e2e="sidenav-element-projectgrants"]').click(); + cy.get('[data-e2e="create-project-grant-button"]').click(); + cy.get('[data-e2e="add-org-input"]').type(defaultOrg); + cy.get('mat-option').contains(defaultOrg).click(); + cy.get('button').should('be.enabled'); + cy.get('[data-e2e="project-grant-continue"]').first().click(); + cy.get(rowSelector).find('input').click({ force: true }); + cy.get('[data-e2e="save-project-grant-button"]').click(); + cy.contains('tr', defaultOrg); + cy.contains('tr', testRoleName); + }); + }); + describe('edit project', () => { beforeEach('ensure it exists', () => { cy.get('@ctx').then((ctx) => { - ensureProjectExists(ctx.api, testProjectNameDelete); + ensureProjectExists(ctx.api, testProjectNameDelete).as('projectId'); cy.visit(`/projects`); }); }); diff --git a/e2e/cypress/e2e/quotas/quotas.cy.ts b/e2e/cypress/e2e/quotas/quotas.cy.ts index ada143105..e3b650479 100644 --- a/e2e/cypress/e2e/quotas/quotas.cy.ts +++ b/e2e/cypress/e2e/quotas/quotas.cy.ts @@ -130,12 +130,12 @@ describe('quotas', () => { expect(res.status).to.equal(429); }); // visit limited console - cy.visit('/users/me'); - cy.contains('#authenticated-requests-exhausted-dialog button', 'Continue').click(); - const upgradeInstancePage = `https://example.com/instances/${ctx.instanceId}`; - cy.origin(upgradeInstancePage, { args: { upgradeInstancePage } }, ({ upgradeInstancePage }) => { - cy.location('href').should('equal', upgradeInstancePage); - }); + // cy.visit('/users/me'); + // cy.contains('#authenticated-requests-exhausted-dialog button', 'Continue').click(); + // const upgradeInstancePage = `https://example.com/instances/${ctx.instanceId}`; + // cy.origin(upgradeInstancePage, { args: { upgradeInstancePage } }, ({ upgradeInstancePage }) => { + // cy.location('href').should('equal', upgradeInstancePage); + // }); // upgrade instance ensureQuotaIsRemoved(ctx, Unit.AuthenticatedRequests); // visit upgraded console again diff --git a/e2e/cypress/support/login/users.ts b/e2e/cypress/support/login/users.ts index d3a1a08c1..db230b1f5 100644 --- a/e2e/cypress/support/login/users.ts +++ b/e2e/cypress/support/login/users.ts @@ -82,6 +82,8 @@ export function login( onAuthenticated ? onAuthenticated() : null; + cy.wait(1000); + cy.visit('/'); cy.get('[data-e2e=authenticated-welcome]', { diff --git a/go.mod b/go.mod index 74ff7c774..18077ccc0 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,12 @@ module github.com/zitadel/zitadel -go 1.19 +go 1.20 require ( cloud.google.com/go/storage v1.30.1 github.com/BurntSushi/toml v1.2.1 github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.13.0 - github.com/Masterminds/sprig v2.22.0+incompatible github.com/Masterminds/squirrel v1.5.4 github.com/VictoriaMetrics/fastcache v1.12.1 github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b @@ -15,14 +14,15 @@ require ( github.com/benbjohnson/clock v1.3.0 github.com/boombuler/barcode v1.0.1 github.com/cockroachdb/cockroach-go/v2 v2.3.3 + github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be github.com/descope/virtualwebauthn v1.0.2 github.com/dop251/goja v0.0.0-20230402114112-623f9dda9079 github.com/dop251/goja_nodejs v0.0.0-20230322100729-2550c7b6c124 github.com/drone/envsubst v1.0.3 github.com/envoyproxy/protoc-gen-validate v0.10.1 + github.com/fatih/color v1.13.0 github.com/go-ldap/ldap/v3 v3.4.4 github.com/go-webauthn/webauthn v0.8.2 - github.com/golang/glog v1.1.1 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 github.com/gorilla/csrf v1.7.1 @@ -59,7 +59,8 @@ require ( github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203 github.com/ttacon/libphonenumber v1.2.1 github.com/zitadel/logging v0.3.4 - github.com/zitadel/oidc/v2 v2.6.3 + github.com/zitadel/oidc/v2 v2.7.0 + github.com/zitadel/passwap v0.2.0 github.com/zitadel/saml v0.0.11 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 @@ -71,16 +72,15 @@ require ( go.opentelemetry.io/otel/sdk v1.14.0 go.opentelemetry.io/otel/sdk/metric v0.37.0 go.opentelemetry.io/otel/trace v1.14.0 - golang.org/x/crypto v0.9.0 - golang.org/x/net v0.10.0 - golang.org/x/oauth2 v0.8.0 - golang.org/x/sync v0.1.0 - golang.org/x/text v0.9.0 - golang.org/x/tools v0.7.0 - google.golang.org/api v0.115.0 - google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd - google.golang.org/grpc v1.54.0 - google.golang.org/protobuf v1.30.0 + golang.org/x/crypto v0.11.0 + golang.org/x/net v0.12.0 + golang.org/x/oauth2 v0.10.0 + golang.org/x/sync v0.2.0 + golang.org/x/text v0.11.0 + google.golang.org/api v0.126.0 + google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc + google.golang.org/grpc v1.55.0 + google.golang.org/protobuf v1.31.0 gopkg.in/square/go-jose.v2 v2.6.0 sigs.k8s.io/yaml v1.3.0 ) @@ -91,25 +91,29 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-webauthn/revoke v0.1.9 // indirect + github.com/golang/glog v1.1.1 // indirect github.com/google/go-tpm v0.3.3 // indirect github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect + github.com/google/s2a-go v0.1.4 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/smartystreets/assertions v1.0.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect go.uber.org/multierr v1.11.0 // indirect + google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect ) require ( - cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go v0.110.2 // indirect + cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.0.0 // indirect cloud.google.com/go/trace v1.9.0 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver v1.5.0 // indirect github.com/amdonov/xmlsig v0.1.0 // indirect github.com/beevik/etree v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -130,7 +134,6 @@ require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -144,13 +147,11 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.8.0 // indirect + github.com/googleapis/gax-go/v2 v2.11.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/h2non/filetype v1.1.3 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.15 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -170,8 +171,6 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.0 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 // indirect @@ -195,8 +194,7 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.8.0 + golang.org/x/sys v0.10.0 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 162c573e2..e69bad2e3 100644 --- a/go.sum +++ b/go.sum @@ -17,16 +17,16 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA= +cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -67,14 +67,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.37.0 h1:k5x4SiDgKS8wVQO/ww1fnoh5gwYEg6Wsi+1z5kB9uDM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.37.0/go.mod h1:oEccMakRmMNrayCPR+5OmZE/aeXmTPzUtmomEXIPBdI= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -156,6 +150,8 @@ github.com/cockroachdb/cockroach-go/v2 v2.3.3 h1:fNmtG6XhoA1DhdDCIu66YyGSsNb1szj github.com/cockroachdb/cockroach-go/v2 v2.3.3/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -247,6 +243,8 @@ github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6Ni github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -258,7 +256,6 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -417,6 +414,8 @@ github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8q github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk= github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -425,8 +424,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9 github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -491,14 +490,10 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -639,12 +634,17 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= @@ -660,8 +660,6 @@ github.com/minio/minio-go/v7 v7.0.50/go.mod h1:IbbodHyjUAguneyucUaahv+VMNs/EOTV9 github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -671,8 +669,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -900,8 +896,10 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zitadel/logging v0.3.4 h1:9hZsTjMMTE3X2LUi0xcF9Q9EdLo+FAezeu52ireBbHM= github.com/zitadel/logging v0.3.4/go.mod h1:aPpLQhE+v6ocNK0TWrBrd363hZ95KcI17Q1ixAQwZF0= -github.com/zitadel/oidc/v2 v2.6.3 h1:YY87cAcdI+3voZqcRU2RGz3Pxky/2KsjDmYDVb6EgWw= -github.com/zitadel/oidc/v2 v2.6.3/go.mod h1:2LrbdKYLSgKxXBfct56ev4e186J7TXotlZxb6tExOO4= +github.com/zitadel/oidc/v2 v2.7.0 h1:IGX4EDk6tegTjUSsZDWeTfLseFU0BdJ/Glf1tgys2lU= +github.com/zitadel/oidc/v2 v2.7.0/go.mod h1:zkUkVJS0sDVy9m0UA9RgO3f8i/C0rtjvXU36UJj7T+0= +github.com/zitadel/passwap v0.2.0 h1:rkYrax9hfRIpVdXJ7pS8JHkQOhuQTdZQxEhsY0dFFrU= +github.com/zitadel/passwap v0.2.0/go.mod h1:KRTL4LL8ugJIn2xLoQYZf5t4kDyr7w41uq3XqvUlO6w= github.com/zitadel/saml v0.0.11 h1:kObucnBrcu1PHCO7RGT0iVeuJL/5I50gUgr40S41nMs= github.com/zitadel/saml v0.0.11/go.mod h1:YGWAvPZRv4DbEZ78Ht/2P0AWzGn+6WGhFf90PMXl0Po= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -980,11 +978,12 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1022,8 +1021,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1074,8 +1071,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1086,8 +1083,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1100,8 +1097,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1160,7 +1157,9 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1168,11 +1167,12 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1191,8 +1191,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1257,8 +1257,6 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1287,8 +1285,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.115.0 h1:6FFkVvStt4YqXSx3azKyzj7fXerGnVlLJ/eud01nBDE= -google.golang.org/api v0.115.0/go.mod h1:9cD4/t6uvd9naoEJFA+M96d0IuB6BqFuyhpw68+mRGg= +google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1339,8 +1337,12 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1367,8 +1369,9 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1382,8 +1385,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/api/assets/asset.go b/internal/api/assets/asset.go index f570b7dd9..08ba7130a 100644 --- a/internal/api/assets/asset.go +++ b/internal/api/assets/asset.go @@ -190,6 +190,10 @@ func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.Respon return } if err = GetAsset(w, r, resourceOwner, objectName, s.Storage()); err != nil { + if strings.Contains(err.Error(), "DATAB-pCP8P") { + s.ErrorHandler()(w, r, err, http.StatusNotFound) + return + } s.ErrorHandler()(w, r, err, http.StatusInternalServerError) } } diff --git a/internal/api/assets/generator/asset_generator.go b/internal/api/assets/generator/asset_generator.go index a30112a82..51268634c 100644 --- a/internal/api/assets/generator/asset_generator.go +++ b/internal/api/assets/generator/asset_generator.go @@ -128,7 +128,9 @@ func GenerateAssetHandler(configFilePath, handlerPrefix string, authz, router, d logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate docs") } -const authzTmpl = `package {{.GoPkgName}} +const authzTmpl = `// Code generated by assets generator. DO NOT EDIT. + +package {{.GoPkgName}} import ( "github.com/zitadel/zitadel/internal/api/authz" @@ -159,7 +161,9 @@ var {{.Name}}_AuthMethods = authz.MethodMapping { } ` -const routerTmpl = `package {{.GoPkgName}} +const routerTmpl = `// Code generated by assets generator. DO NOT EDIT. + +package {{.GoPkgName}} import ( "github.com/gorilla/mux" diff --git a/internal/api/authz/context_mock.go b/internal/api/authz/context_mock.go index e7b5c4017..6badf1586 100644 --- a/internal/api/authz/context_mock.go +++ b/internal/api/authz/context_mock.go @@ -4,11 +4,11 @@ import "context" func NewMockContext(instanceID, orgID, userID string) context.Context { ctx := context.WithValue(context.Background(), dataKey, CtxData{UserID: userID, OrgID: orgID}) - return context.WithValue(ctx, instanceKey, instanceID) + return context.WithValue(ctx, instanceKey, &instance{id: instanceID}) } func NewMockContextWithPermissions(instanceID, orgID, userID string, permissions []string) context.Context { ctx := context.WithValue(context.Background(), dataKey, CtxData{UserID: userID, OrgID: orgID}) - ctx = context.WithValue(ctx, instanceKey, instanceID) + ctx = context.WithValue(ctx, instanceKey, &instance{id: instanceID}) return context.WithValue(ctx, requestPermissionsKey, permissions) } diff --git a/internal/api/authz/token.go b/internal/api/authz/token.go index b56d042da..615543093 100644 --- a/internal/api/authz/token.go +++ b/internal/api/authz/token.go @@ -20,7 +20,8 @@ import ( const ( BearerPrefix = "Bearer " - SessionTokenFormat = "sess_%s:%s" + SessionTokenPrefix = "sess_" + SessionTokenFormat = SessionTokenPrefix + "%s:%s" ) type TokenVerifier struct { diff --git a/internal/api/call/duration.go b/internal/api/call/duration.go index 24573aa36..b3334de95 100644 --- a/internal/api/call/duration.go +++ b/internal/api/call/duration.go @@ -9,12 +9,18 @@ type durationKey struct{} var key *durationKey = (*durationKey)(nil) -// WithTimestamp sets [time.Now()] adds the call field to the context -// if it's not already set +// WithTimestamp sets [time.Now()] to the call field in the context +// if it's not already set. func WithTimestamp(parent context.Context) context.Context { if parent.Value(key) != nil { return parent } + return ResetTimestamp(parent) +} + +// ResetTimestamp sets [time.Now()] to the call field in the context, +// overwriting any previously set call timestamp. +func ResetTimestamp(parent context.Context) context.Context { return context.WithValue(parent, key, time.Now()) } diff --git a/internal/api/grpc/admin/export.go b/internal/api/grpc/admin/export.go index bd5387364..678b81048 100644 --- a/internal/api/grpc/admin/export.go +++ b/internal/api/grpc/admin/export.go @@ -430,6 +430,7 @@ func (s *Server) getLoginPolicy(ctx context.Context, orgID string, orgIDPs []str AllowRegister: queriedLogin.AllowRegister, AllowExternalIdp: queriedLogin.AllowExternalIDPs, ForceMfa: queriedLogin.ForceMFA, + ForceMfaLocalOnly: queriedLogin.ForceMFALocalOnly, PasswordlessType: policy_pb.PasswordlessType(queriedLogin.PasswordlessType), HidePasswordReset: queriedLogin.HidePasswordReset, IgnoreUnknownUsernames: queriedLogin.IgnoreUnknownUsernames, @@ -577,15 +578,14 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w } if withPasswords { ctx, pwspan := tracing.NewSpan(ctx) - hashedPassword, hashAlgorithm, err := s.query.GetHumanPassword(ctx, org, user.ID) + encodedHash, err := s.query.GetHumanPassword(ctx, org, user.ID) pwspan.EndWithError(err) if err != nil && !caos_errors.IsNotFound(err) { return nil, nil, nil, nil, err } - if err == nil && hashedPassword != nil { + if err == nil && encodedHash != "" { dataUser.User.HashedPassword = &management_pb.ImportHumanUserRequest_HashedPassword{ - Value: string(hashedPassword), - Algorithm: hashAlgorithm, + Value: encodedHash, } } } diff --git a/internal/api/grpc/admin/iam_settings.go b/internal/api/grpc/admin/iam_settings.go index cfbf28563..a4be248ee 100644 --- a/internal/api/grpc/admin/iam_settings.go +++ b/internal/api/grpc/admin/iam_settings.go @@ -18,6 +18,7 @@ func (s *Server) ListSecretGenerators(ctx context.Context, req *admin_pb.ListSec return nil, err } return &admin_pb.ListSecretGeneratorsResponse{ + Result: SecretGeneratorsToPb(result.SecretGenerators), Details: object.ToListDetails(result.Count, result.Sequence, result.Timestamp), }, nil } diff --git a/internal/api/grpc/admin/iam_settings_converter.go b/internal/api/grpc/admin/iam_settings_converter.go index c93f8fbf4..7dfd1a381 100644 --- a/internal/api/grpc/admin/iam_settings_converter.go +++ b/internal/api/grpc/admin/iam_settings_converter.go @@ -62,6 +62,14 @@ func UpdateSecretGeneratorToConfig(req *admin_pb.UpdateSecretGeneratorRequest) * } } +func SecretGeneratorsToPb(generators []*query.SecretGenerator) []*settings_pb.SecretGenerator { + list := make([]*settings_pb.SecretGenerator, len(generators)) + for i, generator := range generators { + list[i] = SecretGeneratorToPb(generator) + } + return list +} + func SecretGeneratorToPb(generator *query.SecretGenerator) *settings_pb.SecretGenerator { mapped := &settings_pb.SecretGenerator{ Length: uint32(generator.Length), diff --git a/internal/api/grpc/admin/login_policy_converter.go b/internal/api/grpc/admin/login_policy_converter.go index 24fee2d00..68c1f879d 100644 --- a/internal/api/grpc/admin/login_policy_converter.go +++ b/internal/api/grpc/admin/login_policy_converter.go @@ -14,6 +14,7 @@ func updateLoginPolicyToCommand(p *admin_pb.UpdateLoginPolicyRequest) *command.C AllowRegister: p.AllowRegister, AllowExternalIDP: p.AllowExternalIdp, ForceMFA: p.ForceMfa, + ForceMFALocalOnly: p.ForceMfaLocalOnly, PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType), HidePasswordReset: p.HidePasswordReset, IgnoreUnknownUsernames: p.IgnoreUnknownUsernames, diff --git a/internal/api/grpc/management/policy_label_converter.go b/internal/api/grpc/management/policy_label_converter.go index 3ad0b3329..9c399cfe3 100644 --- a/internal/api/grpc/management/policy_label_converter.go +++ b/internal/api/grpc/management/policy_label_converter.go @@ -10,9 +10,11 @@ func AddLabelPolicyToDomain(p *mgmt_pb.AddCustomLabelPolicyRequest) *domain.Labe PrimaryColor: p.PrimaryColor, BackgroundColor: p.BackgroundColor, WarnColor: p.WarnColor, + FontColor: p.FontColor, PrimaryColorDark: p.PrimaryColorDark, BackgroundColorDark: p.BackgroundColorDark, WarnColorDark: p.WarnColorDark, + FontColorDark: p.FontColorDark, HideLoginNameSuffix: p.HideLoginNameSuffix, DisableWatermark: p.DisableWatermark, } diff --git a/internal/api/grpc/management/policy_login_converter.go b/internal/api/grpc/management/policy_login_converter.go index 2e41d1c8f..0e000e427 100644 --- a/internal/api/grpc/management/policy_login_converter.go +++ b/internal/api/grpc/management/policy_login_converter.go @@ -15,6 +15,7 @@ func AddLoginPolicyToCommand(p *mgmt_pb.AddCustomLoginPolicyRequest) *command.Ad AllowRegister: p.AllowRegister, AllowExternalIDP: p.AllowExternalIdp, ForceMFA: p.ForceMfa, + ForceMFALocalOnly: p.ForceMfaLocalOnly, PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType), HidePasswordReset: p.HidePasswordReset, IgnoreUnknownUsernames: p.IgnoreUnknownUsernames, @@ -49,6 +50,7 @@ func updateLoginPolicyToCommand(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *comm AllowRegister: p.AllowRegister, AllowExternalIDP: p.AllowExternalIdp, ForceMFA: p.ForceMfa, + ForceMFALocalOnly: p.ForceMfaLocalOnly, PasswordlessType: policy_grpc.PasswordlessTypeToDomain(p.PasswordlessType), HidePasswordReset: p.HidePasswordReset, IgnoreUnknownUsernames: p.IgnoreUnknownUsernames, diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index 7b1b109ed..5375ce5fb 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -854,7 +854,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *mgmt_pb.List } func (s *Server) AddPersonalAccessToken(ctx context.Context, req *mgmt_pb.AddPersonalAccessTokenRequest) (*mgmt_pb.AddPersonalAccessTokenResponse, error) { - scopes := []string{oidc.ScopeOpenID, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner} + scopes := []string{oidc.ScopeOpenID, oidc.ScopeProfile, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner} pat := AddPersonalAccessTokenRequestToCommand(req, authz.GetCtxData(ctx).OrgID, scopes, domain.UserTypeMachine) details, err := s.command.AddPersonalAccessToken(ctx, pat) if err != nil { diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go index 3c969c2a1..a3f7760b0 100644 --- a/internal/api/grpc/management/user_converter.go +++ b/internal/api/grpc/management/user_converter.go @@ -121,9 +121,7 @@ func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human human.Password.ChangeRequired = req.PasswordChangeRequired } - if req.HashedPassword != nil && req.HashedPassword.Value != "" && req.HashedPassword.Algorithm != "" { - human.HashedPassword = domain.NewHashedPassword(req.HashedPassword.Value, req.HashedPassword.Algorithm) - } + human.HashedPassword = req.GetHashedPassword().GetValue() links = make([]*domain.UserIDPLink, len(req.Idps)) for i, idp := range req.Idps { links[i] = &domain.UserIDPLink{ diff --git a/internal/api/grpc/management/user_integration_test.go b/internal/api/grpc/management/user_integration_test.go new file mode 100644 index 000000000..c1682a5cc --- /dev/null +++ b/internal/api/grpc/management/user_integration_test.go @@ -0,0 +1,87 @@ +//go:build integration + +package management_test + +import ( + "context" + "os" + "testing" + "time" + + "github.com/zitadel/zitadel/internal/integration" + "github.com/zitadel/zitadel/pkg/grpc/management" +) + +var ( + CTX context.Context + Tester *integration.Tester + Client management.ManagementServiceClient +) + +func TestMain(m *testing.M) { + os.Exit(func() int { + ctx, errCtx, cancel := integration.Contexts(3 * time.Minute) + defer cancel() + + Tester = integration.NewTester(ctx) + defer Tester.Done() + + CTX, _ = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx + Client = Tester.Client.Mgmt + return m.Run() + }()) +} + +// TestImport_and_Get reproduces https://github.com/zitadel/zitadel/issues/5808 +// which led to consistency issues due the call timestamp not being +// updated after a bulk Trigger. +// This test Imports a user and directly tries to Get it, 100 times in a loop. +// When the bug still existed, some (between 1 to 7 out of 100) +// Get calls would return a Not Found error. + +/* Test disabled because it breaks the pipeline. +func TestImport_and_Get(t *testing.T) { + const N = 100 + var misses int + + for i := 0; i < N; i++ { + firstName := strconv.Itoa(i) + t.Run(firstName, func(t *testing.T) { + // create unique names. + lastName := strconv.FormatInt(time.Now().Unix(), 10) + userName := strings.Join([]string{firstName, lastName}, "_") + email := strings.Join([]string{userName, "zitadel.com"}, "@") + + res, err := Client.ImportHumanUser(CTX, &management.ImportHumanUserRequest{ + UserName: userName, + Profile: &management.ImportHumanUserRequest_Profile{ + FirstName: firstName, + LastName: lastName, + PreferredLanguage: language.Afrikaans.String(), + Gender: user.Gender_GENDER_DIVERSE, + }, + Email: &management.ImportHumanUserRequest_Email{ + Email: email, + IsEmailVerified: true, + }, + }) + require.NoError(t, err) + + _, err = Client.GetUserByID(CTX, &management.GetUserByIDRequest{Id: res.GetUserId()}) + + if s, ok := status.FromError(err); ok { + if s == nil { + return + } + if s.Code() == codes.NotFound { + t.Log(s) + misses++ + return + } + } + require.NoError(t, err) // catch and fail on any other error + }) + } + assert.Zerof(t, misses, "Not Found errors %d out of %d", misses, N) +} +*/ diff --git a/internal/api/grpc/metadata/metadata.go b/internal/api/grpc/metadata/metadata.go index 731dda98a..e54007e09 100644 --- a/internal/api/grpc/metadata/metadata.go +++ b/internal/api/grpc/metadata/metadata.go @@ -70,5 +70,5 @@ func MetadataQueryToQuery(query *meta_pb.MetadataQuery) (query.SearchQuery, erro } func MetadataKeyQueryToQuery(q *meta_pb.MetadataKeyQuery) (query.SearchQuery, error) { - return query.NewUserMetadataKeySearchQuery(q.Key, object.TextMethodToQuery(q.Method)) + return query.NewOrgMetadataKeySearchQuery(q.Key, object.TextMethodToQuery(q.Method)) } diff --git a/internal/api/grpc/oidc/v2/oidc.go b/internal/api/grpc/oidc/v2/oidc.go new file mode 100644 index 000000000..4675dfc6f --- /dev/null +++ b/internal/api/grpc/oidc/v2/oidc.go @@ -0,0 +1,204 @@ +package oidc + +import ( + "context" + + "github.com/zitadel/logging" + "github.com/zitadel/oidc/v2/pkg/op" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/grpc/object/v2" + "github.com/zitadel/zitadel/internal/api/http" + "github.com/zitadel/zitadel/internal/api/oidc" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/query" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" +) + +func (s *Server) GetAuthRequest(ctx context.Context, req *oidc_pb.GetAuthRequestRequest) (*oidc_pb.GetAuthRequestResponse, error) { + authRequest, err := s.query.AuthRequestByID(ctx, true, req.GetAuthRequestId(), true) + if err != nil { + logging.WithError(err).Error("query authRequest by ID") + return nil, err + } + return &oidc_pb.GetAuthRequestResponse{ + AuthRequest: authRequestToPb(authRequest), + }, nil +} + +func authRequestToPb(a *query.AuthRequest) *oidc_pb.AuthRequest { + pba := &oidc_pb.AuthRequest{ + Id: a.ID, + CreationDate: timestamppb.New(a.CreationDate), + ClientId: a.ClientID, + Scope: a.Scope, + RedirectUri: a.RedirectURI, + Prompt: promptsToPb(a.Prompt), + UiLocales: a.UiLocales, + LoginHint: a.LoginHint, + HintUserId: a.HintUserID, + } + if a.MaxAge != nil { + pba.MaxAge = durationpb.New(*a.MaxAge) + } + return pba +} + +func promptsToPb(promps []domain.Prompt) []oidc_pb.Prompt { + out := make([]oidc_pb.Prompt, len(promps)) + for i, p := range promps { + out[i] = promptToPb(p) + } + return out +} + +func promptToPb(p domain.Prompt) oidc_pb.Prompt { + switch p { + case domain.PromptUnspecified: + return oidc_pb.Prompt_PROMPT_UNSPECIFIED + case domain.PromptNone: + return oidc_pb.Prompt_PROMPT_NONE + case domain.PromptLogin: + return oidc_pb.Prompt_PROMPT_LOGIN + case domain.PromptConsent: + return oidc_pb.Prompt_PROMPT_CONSENT + case domain.PromptSelectAccount: + return oidc_pb.Prompt_PROMPT_SELECT_ACCOUNT + case domain.PromptCreate: + return oidc_pb.Prompt_PROMPT_CREATE + default: + return oidc_pb.Prompt_PROMPT_UNSPECIFIED + } +} + +func (s *Server) CreateCallback(ctx context.Context, req *oidc_pb.CreateCallbackRequest) (*oidc_pb.CreateCallbackResponse, error) { + switch v := req.GetCallbackKind().(type) { + case *oidc_pb.CreateCallbackRequest_Error: + return s.failAuthRequest(ctx, req.GetAuthRequestId(), v.Error) + case *oidc_pb.CreateCallbackRequest_Session: + return s.linkSessionToAuthRequest(ctx, req.GetAuthRequestId(), v.Session) + default: + return nil, errors.ThrowUnimplementedf(nil, "OIDCv2-zee7A", "verification oneOf %T in method CreateCallback not implemented", v) + } +} + +func (s *Server) failAuthRequest(ctx context.Context, authRequestID string, ae *oidc_pb.AuthorizationError) (*oidc_pb.CreateCallbackResponse, error) { + details, aar, err := s.command.FailAuthRequest(ctx, authRequestID, errorReasonToDomain(ae.GetError())) + if err != nil { + return nil, err + } + authReq := &oidc.AuthRequestV2{CurrentAuthRequest: aar} + callback, err := oidc.CreateErrorCallbackURL(authReq, errorReasonToOIDC(ae.GetError()), ae.GetErrorDescription(), ae.GetErrorUri(), s.op) + if err != nil { + return nil, err + } + return &oidc_pb.CreateCallbackResponse{ + Details: object.DomainToDetailsPb(details), + CallbackUrl: callback, + }, nil +} + +func (s *Server) linkSessionToAuthRequest(ctx context.Context, authRequestID string, session *oidc_pb.Session) (*oidc_pb.CreateCallbackResponse, error) { + details, aar, err := s.command.LinkSessionToAuthRequest(ctx, authRequestID, session.GetSessionId(), session.GetSessionToken(), true) + if err != nil { + return nil, err + } + authReq := &oidc.AuthRequestV2{CurrentAuthRequest: aar} + ctx = op.ContextWithIssuer(ctx, http.BuildOrigin(authz.GetInstance(ctx).RequestedHost(), s.externalSecure)) + var callback string + if aar.ResponseType == domain.OIDCResponseTypeCode { + callback, err = oidc.CreateCodeCallbackURL(ctx, authReq, s.op) + } else { + callback, err = oidc.CreateTokenCallbackURL(ctx, authReq, s.op) + } + if err != nil { + return nil, err + } + return &oidc_pb.CreateCallbackResponse{ + Details: object.DomainToDetailsPb(details), + CallbackUrl: callback, + }, nil +} + +func errorReasonToDomain(errorReason oidc_pb.ErrorReason) domain.OIDCErrorReason { + switch errorReason { + case oidc_pb.ErrorReason_ERROR_REASON_UNSPECIFIED: + return domain.OIDCErrorReasonUnspecified + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST: + return domain.OIDCErrorReasonInvalidRequest + case oidc_pb.ErrorReason_ERROR_REASON_UNAUTHORIZED_CLIENT: + return domain.OIDCErrorReasonUnauthorizedClient + case oidc_pb.ErrorReason_ERROR_REASON_ACCESS_DENIED: + return domain.OIDCErrorReasonAccessDenied + case oidc_pb.ErrorReason_ERROR_REASON_UNSUPPORTED_RESPONSE_TYPE: + return domain.OIDCErrorReasonUnsupportedResponseType + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_SCOPE: + return domain.OIDCErrorReasonInvalidScope + case oidc_pb.ErrorReason_ERROR_REASON_SERVER_ERROR: + return domain.OIDCErrorReasonServerError + case oidc_pb.ErrorReason_ERROR_REASON_TEMPORARY_UNAVAILABLE: + return domain.OIDCErrorReasonTemporaryUnavailable + case oidc_pb.ErrorReason_ERROR_REASON_INTERACTION_REQUIRED: + return domain.OIDCErrorReasonInteractionRequired + case oidc_pb.ErrorReason_ERROR_REASON_LOGIN_REQUIRED: + return domain.OIDCErrorReasonLoginRequired + case oidc_pb.ErrorReason_ERROR_REASON_ACCOUNT_SELECTION_REQUIRED: + return domain.OIDCErrorReasonAccountSelectionRequired + case oidc_pb.ErrorReason_ERROR_REASON_CONSENT_REQUIRED: + return domain.OIDCErrorReasonConsentRequired + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST_URI: + return domain.OIDCErrorReasonInvalidRequestURI + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST_OBJECT: + return domain.OIDCErrorReasonInvalidRequestObject + case oidc_pb.ErrorReason_ERROR_REASON_REQUEST_NOT_SUPPORTED: + return domain.OIDCErrorReasonRequestNotSupported + case oidc_pb.ErrorReason_ERROR_REASON_REQUEST_URI_NOT_SUPPORTED: + return domain.OIDCErrorReasonRequestURINotSupported + case oidc_pb.ErrorReason_ERROR_REASON_REGISTRATION_NOT_SUPPORTED: + return domain.OIDCErrorReasonRegistrationNotSupported + default: + return domain.OIDCErrorReasonUnspecified + } +} + +func errorReasonToOIDC(reason oidc_pb.ErrorReason) string { + switch reason { + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST: + return "invalid_request" + case oidc_pb.ErrorReason_ERROR_REASON_UNAUTHORIZED_CLIENT: + return "unauthorized_client" + case oidc_pb.ErrorReason_ERROR_REASON_ACCESS_DENIED: + return "access_denied" + case oidc_pb.ErrorReason_ERROR_REASON_UNSUPPORTED_RESPONSE_TYPE: + return "unsupported_response_type" + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_SCOPE: + return "invalid_scope" + case oidc_pb.ErrorReason_ERROR_REASON_TEMPORARY_UNAVAILABLE: + return "temporarily_unavailable" + case oidc_pb.ErrorReason_ERROR_REASON_INTERACTION_REQUIRED: + return "interaction_required" + case oidc_pb.ErrorReason_ERROR_REASON_LOGIN_REQUIRED: + return "login_required" + case oidc_pb.ErrorReason_ERROR_REASON_ACCOUNT_SELECTION_REQUIRED: + return "account_selection_required" + case oidc_pb.ErrorReason_ERROR_REASON_CONSENT_REQUIRED: + return "consent_required" + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST_URI: + return "invalid_request_uri" + case oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST_OBJECT: + return "invalid_request_object" + case oidc_pb.ErrorReason_ERROR_REASON_REQUEST_NOT_SUPPORTED: + return "request_not_supported" + case oidc_pb.ErrorReason_ERROR_REASON_REQUEST_URI_NOT_SUPPORTED: + return "request_uri_not_supported" + case oidc_pb.ErrorReason_ERROR_REASON_REGISTRATION_NOT_SUPPORTED: + return "registration_not_supported" + case oidc_pb.ErrorReason_ERROR_REASON_UNSPECIFIED, oidc_pb.ErrorReason_ERROR_REASON_SERVER_ERROR: + fallthrough + default: + return "server_error" + } +} diff --git a/internal/api/grpc/oidc/v2/oidc_integration_test.go b/internal/api/grpc/oidc/v2/oidc_integration_test.go new file mode 100644 index 000000000..b48bfc083 --- /dev/null +++ b/internal/api/grpc/oidc/v2/oidc_integration_test.go @@ -0,0 +1,254 @@ +//go:build integration + +package oidc_test + +import ( + "context" + "net/url" + "os" + "regexp" + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/zitadel/zitadel/internal/integration" + object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" + session "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha" + user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha" +) + +var ( + CTX context.Context + Tester *integration.Tester + Client oidc_pb.OIDCServiceClient + User *user.AddHumanUserResponse +) + +const ( + redirectURI = "oidcintegrationtest://callback" + redirectURIImplicit = "http://localhost:9999/callback" + logoutRedirectURI = "oidcintegrationtest://logged-out" +) + +func TestMain(m *testing.M) { + os.Exit(func() int { + ctx, _, cancel := integration.Contexts(5 * time.Minute) + defer cancel() + + Tester = integration.NewTester(ctx) + defer Tester.Done() + Client = Tester.Client.OIDCv2 + + CTX = Tester.WithAuthorization(ctx, integration.OrgOwner) + User = Tester.CreateHumanUser(CTX) + return m.Run() + }()) +} + +func TestServer_GetAuthRequest(t *testing.T) { + project, err := Tester.CreateProject(CTX) + require.NoError(t, err) + client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + require.NoError(t, err) + authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI) + require.NoError(t, err) + now := time.Now() + + tests := []struct { + name string + AuthRequestID string + want *oidc_pb.GetAuthRequestResponse + wantErr bool + }{ + { + name: "Not found", + AuthRequestID: "123", + wantErr: true, + }, + { + name: "success", + AuthRequestID: authRequestID, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Client.GetAuthRequest(CTX, &oidc_pb.GetAuthRequestRequest{ + AuthRequestId: tt.AuthRequestID, + }) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + authRequest := got.GetAuthRequest() + assert.NotNil(t, authRequest) + assert.Equal(t, authRequestID, authRequest.GetId()) + assert.WithinRange(t, authRequest.GetCreationDate().AsTime(), now.Add(-time.Second), now.Add(time.Second)) + assert.Contains(t, authRequest.GetScope(), "openid") + }) + } +} + +func TestServer_CreateCallback(t *testing.T) { + project, err := Tester.CreateProject(CTX) + require.NoError(t, err) + client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + require.NoError(t, err) + sessionResp, err := Tester.Client.SessionV2.CreateSession(CTX, &session.CreateSessionRequest{ + Checks: &session.Checks{ + User: &session.CheckUser{ + Search: &session.CheckUser_UserId{ + UserId: Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, + }, + }, + }, + }) + require.NoError(t, err) + + tests := []struct { + name string + req *oidc_pb.CreateCallbackRequest + AuthError string + want *oidc_pb.CreateCallbackResponse + wantURL *url.URL + wantErr bool + }{ + { + name: "Not found", + req: &oidc_pb.CreateCallbackRequest{ + AuthRequestId: "123", + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionResp.GetSessionId(), + SessionToken: sessionResp.GetSessionToken(), + }, + }, + }, + wantErr: true, + }, + { + name: "session not found", + req: &oidc_pb.CreateCallbackRequest{ + AuthRequestId: func() string { + authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI) + require.NoError(t, err) + return authRequestID + }(), + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: "foo", + SessionToken: "bar", + }, + }, + }, + wantErr: true, + }, + { + name: "session token invalid", + req: &oidc_pb.CreateCallbackRequest{ + AuthRequestId: func() string { + authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI) + require.NoError(t, err) + return authRequestID + }(), + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionResp.GetSessionId(), + SessionToken: "bar", + }, + }, + }, + wantErr: true, + }, + { + name: "fail callback", + req: &oidc_pb.CreateCallbackRequest{ + AuthRequestId: func() string { + authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI) + require.NoError(t, err) + return authRequestID + }(), + CallbackKind: &oidc_pb.CreateCallbackRequest_Error{ + Error: &oidc_pb.AuthorizationError{ + Error: oidc_pb.ErrorReason_ERROR_REASON_ACCESS_DENIED, + ErrorDescription: gu.Ptr("nope"), + ErrorUri: gu.Ptr("https://example.com/docs"), + }, + }, + }, + want: &oidc_pb.CreateCallbackResponse{ + CallbackUrl: regexp.QuoteMeta(`oidcintegrationtest://callback?error=access_denied&error_description=nope&error_uri=https%3A%2F%2Fexample.com%2Fdocs&state=state`), + Details: &object.Details{ + ResourceOwner: Tester.Instance.InstanceID(), + }, + }, + wantErr: false, + }, + { + name: "code callback", + req: &oidc_pb.CreateCallbackRequest{ + AuthRequestId: func() string { + authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI) + require.NoError(t, err) + return authRequestID + }(), + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionResp.GetSessionId(), + SessionToken: sessionResp.GetSessionToken(), + }, + }, + }, + want: &oidc_pb.CreateCallbackResponse{ + CallbackUrl: `oidcintegrationtest:\/\/callback\?code=(.*)&state=state`, + Details: &object.Details{ + ResourceOwner: Tester.Instance.InstanceID(), + }, + }, + wantErr: false, + }, + { + name: "implicit", + req: &oidc_pb.CreateCallbackRequest{ + AuthRequestId: func() string { + client, err := Tester.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit) + require.NoError(t, err) + authRequestID, err := Tester.CreateOIDCAuthRequestImplicit(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURIImplicit) + require.NoError(t, err) + return authRequestID + }(), + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionResp.GetSessionId(), + SessionToken: sessionResp.GetSessionToken(), + }, + }, + }, + want: &oidc_pb.CreateCallbackResponse{ + CallbackUrl: `http:\/\/localhost:9999\/callback#access_token=(.*)&expires_in=(.*)&id_token=(.*)&state=state&token_type=Bearer`, + Details: &object.Details{ + ResourceOwner: Tester.Instance.InstanceID(), + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Client.CreateCallback(CTX, tt.req) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + integration.AssertDetails(t, tt.want, got) + if tt.want != nil { + assert.Regexp(t, regexp.MustCompile(tt.want.CallbackUrl), got.GetCallbackUrl()) + } + }) + } +} diff --git a/internal/api/grpc/oidc/v2/oidc_test.go b/internal/api/grpc/oidc/v2/oidc_test.go new file mode 100644 index 000000000..91d795a00 --- /dev/null +++ b/internal/api/grpc/oidc/v2/oidc_test.go @@ -0,0 +1,150 @@ +package oidc + +import ( + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/query" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" +) + +func Test_authRequestToPb(t *testing.T) { + now := time.Now() + arg := &query.AuthRequest{ + ID: "authID", + CreationDate: now, + ClientID: "clientID", + Scope: []string{"a", "b", "c"}, + RedirectURI: "callbackURI", + Prompt: []domain.Prompt{ + domain.PromptUnspecified, + domain.PromptNone, + domain.PromptLogin, + domain.PromptConsent, + domain.PromptSelectAccount, + domain.PromptCreate, + 999, + }, + UiLocales: []string{"en", "fi"}, + LoginHint: gu.Ptr("foo@bar.com"), + MaxAge: gu.Ptr(time.Minute), + HintUserID: gu.Ptr("userID"), + } + want := &oidc_pb.AuthRequest{ + Id: "authID", + CreationDate: timestamppb.New(now), + ClientId: "clientID", + RedirectUri: "callbackURI", + Prompt: []oidc_pb.Prompt{ + oidc_pb.Prompt_PROMPT_UNSPECIFIED, + oidc_pb.Prompt_PROMPT_NONE, + oidc_pb.Prompt_PROMPT_LOGIN, + oidc_pb.Prompt_PROMPT_CONSENT, + oidc_pb.Prompt_PROMPT_SELECT_ACCOUNT, + oidc_pb.Prompt_PROMPT_CREATE, + oidc_pb.Prompt_PROMPT_UNSPECIFIED, + }, + UiLocales: []string{"en", "fi"}, + Scope: []string{"a", "b", "c"}, + LoginHint: gu.Ptr("foo@bar.com"), + MaxAge: durationpb.New(time.Minute), + HintUserId: gu.Ptr("userID"), + } + got := authRequestToPb(arg) + if !proto.Equal(want, got) { + t.Errorf("authRequestToPb() =\n%v\nwant\n%v\n", got, want) + } +} + +func Test_errorReasonToOIDC(t *testing.T) { + tests := []struct { + reason oidc_pb.ErrorReason + want string + }{ + { + reason: oidc_pb.ErrorReason_ERROR_REASON_UNSPECIFIED, + want: "server_error", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST, + want: "invalid_request", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_UNAUTHORIZED_CLIENT, + want: "unauthorized_client", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_ACCESS_DENIED, + want: "access_denied", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_UNSUPPORTED_RESPONSE_TYPE, + want: "unsupported_response_type", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_INVALID_SCOPE, + want: "invalid_scope", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_SERVER_ERROR, + want: "server_error", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_TEMPORARY_UNAVAILABLE, + want: "temporarily_unavailable", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_INTERACTION_REQUIRED, + want: "interaction_required", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_LOGIN_REQUIRED, + want: "login_required", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_ACCOUNT_SELECTION_REQUIRED, + want: "account_selection_required", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_CONSENT_REQUIRED, + want: "consent_required", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST_URI, + want: "invalid_request_uri", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_INVALID_REQUEST_OBJECT, + want: "invalid_request_object", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_REQUEST_NOT_SUPPORTED, + want: "request_not_supported", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_REQUEST_URI_NOT_SUPPORTED, + want: "request_uri_not_supported", + }, + { + reason: oidc_pb.ErrorReason_ERROR_REASON_REGISTRATION_NOT_SUPPORTED, + want: "registration_not_supported", + }, + { + reason: 99999, + want: "server_error", + }, + } + for _, tt := range tests { + t.Run(tt.reason.String(), func(t *testing.T) { + got := errorReasonToOIDC(tt.reason) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/grpc/oidc/v2/server.go b/internal/api/grpc/oidc/v2/server.go new file mode 100644 index 000000000..f15401d1b --- /dev/null +++ b/internal/api/grpc/oidc/v2/server.go @@ -0,0 +1,59 @@ +package oidc + +import ( + "github.com/zitadel/oidc/v2/pkg/op" + "google.golang.org/grpc" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/grpc/server" + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/query" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" +) + +var _ oidc_pb.OIDCServiceServer = (*Server)(nil) + +type Server struct { + oidc_pb.UnimplementedOIDCServiceServer + command *command.Commands + query *query.Queries + + op op.OpenIDProvider + externalSecure bool +} + +type Config struct{} + +func CreateServer( + command *command.Commands, + query *query.Queries, + op op.OpenIDProvider, + externalSecure bool, +) *Server { + return &Server{ + command: command, + query: query, + op: op, + externalSecure: externalSecure, + } +} + +func (s *Server) RegisterServer(grpcServer *grpc.Server) { + oidc_pb.RegisterOIDCServiceServer(grpcServer, s) +} + +func (s *Server) AppName() string { + return oidc_pb.OIDCService_ServiceDesc.ServiceName +} + +func (s *Server) MethodPrefix() string { + return oidc_pb.OIDCService_ServiceDesc.ServiceName +} + +func (s *Server) AuthMethods() authz.MethodMapping { + return oidc_pb.OIDCService_AuthMethods +} + +func (s *Server) RegisterGateway() server.RegisterGatewayFunc { + return oidc_pb.RegisterOIDCServiceHandler +} diff --git a/internal/api/grpc/policy/login_policy.go b/internal/api/grpc/policy/login_policy.go index 3cd191a91..986fd9da2 100644 --- a/internal/api/grpc/policy/login_policy.go +++ b/internal/api/grpc/policy/login_policy.go @@ -18,6 +18,7 @@ func ModelLoginPolicyToPb(policy *query.LoginPolicy) *policy_pb.LoginPolicy { AllowRegister: policy.AllowRegister, AllowExternalIdp: policy.AllowExternalIDPs, ForceMfa: policy.ForceMFA, + ForceMfaLocalOnly: policy.ForceMFALocalOnly, PasswordlessType: ModelPasswordlessTypeToPb(policy.PasswordlessType), HidePasswordReset: policy.HidePasswordReset, IgnoreUnknownUsernames: policy.IgnoreUnknownUsernames, diff --git a/internal/api/grpc/session/v2/session.go b/internal/api/grpc/session/v2/session.go index 8ac29a488..e842476c2 100644 --- a/internal/api/grpc/session/v2/session.go +++ b/internal/api/grpc/session/v2/session.go @@ -16,7 +16,7 @@ import ( ) func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) { - res, err := s.query.SessionByID(ctx, req.GetSessionId(), req.GetSessionToken()) + res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken()) if err != nil { return nil, err } @@ -156,10 +156,11 @@ func userFactorToPb(factor query.SessionUserFactor) *session.UserFactor { return nil } return &session.UserFactor{ - VerifiedAt: timestamppb.New(factor.UserCheckedAt), - Id: factor.UserID, - LoginName: factor.LoginName, - DisplayName: factor.DisplayName, + VerifiedAt: timestamppb.New(factor.UserCheckedAt), + Id: factor.UserID, + LoginName: factor.LoginName, + DisplayName: factor.DisplayName, + OrganisationId: factor.ResourceOwner, } } diff --git a/internal/api/grpc/session/v2/session_integration_test.go b/internal/api/grpc/session/v2/session_integration_test.go index 6c3c2720d..949d78ded 100644 --- a/internal/api/grpc/session/v2/session_integration_test.go +++ b/internal/api/grpc/session/v2/session_integration_test.go @@ -4,14 +4,15 @@ package session_test import ( "context" + "fmt" "os" "testing" "time" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "google.golang.org/grpc/metadata" "github.com/zitadel/zitadel/internal/integration" object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha" @@ -20,11 +21,10 @@ import ( ) var ( - CTX context.Context - Tester *integration.Tester - Client session.SessionServiceClient - User *user.AddHumanUserResponse - GenericOAuthIDPID string + CTX context.Context + Tester *integration.Tester + Client session.SessionServiceClient + User *user.AddHumanUserResponse ) func TestMain(m *testing.M) { @@ -36,38 +36,24 @@ func TestMain(m *testing.M) { defer Tester.Done() Client = Tester.Client.SessionV2 - CTX, _ = Tester.WithSystemAuthorization(ctx, integration.OrgOwner), errCtx + CTX, _ = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx User = Tester.CreateHumanUser(CTX) + Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword) Tester.RegisterUserPasskey(CTX, User.GetUserId()) return m.Run() }()) } -func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, factors ...wantFactor) (s *session.Session) { +func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, factors ...wantFactor) *session.Session { require.NotEmpty(t, id) require.NotEmpty(t, token) -retry: - for { - resp, err := Client.GetSession(CTX, &session.GetSessionRequest{ - SessionId: id, - SessionToken: &token, - }) - if err == nil { - s = resp.GetSession() - break retry - } - if code := status.Convert(err).Code(); code == codes.NotFound || code == codes.PermissionDenied { - select { - case <-CTX.Done(): - t.Fatal(CTX.Err(), err) - case <-time.After(time.Second): - t.Log("retrying GetSession") - continue - } - } - require.NoError(t, err) - } + resp, err := Client.GetSession(CTX, &session.GetSessionRequest{ + SessionId: id, + SessionToken: &token, + }) + require.NoError(t, err) + s := resp.GetSession() assert.Equal(t, id, s.GetId()) assert.WithinRange(t, s.GetCreationDate().AsTime(), time.Now().Add(-window), time.Now().Add(window)) @@ -395,3 +381,51 @@ func TestServer_SetSession_flow(t *testing.T) { verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) }) } + +func Test_ZITADEL_API_missing_authentication(t *testing.T) { + // create new, empty session + createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{Domain: Tester.Config.ExternalDomain}) + require.NoError(t, err) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("Bearer %s", createResp.GetSessionToken())) + sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: createResp.GetSessionId()}) + require.Error(t, err) + require.Nil(t, sessionResp) +} + +func Test_ZITADEL_API_missing_mfa(t *testing.T) { + id, token, _, _ := Tester.CreatePasswordSession(t, CTX, User.GetUserId(), integration.UserPassword) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("Bearer %s", token)) + sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) + require.Error(t, err) + require.Nil(t, sessionResp) +} + +func Test_ZITADEL_API_success(t *testing.T) { + id, token, _, _ := Tester.CreatePasskeySession(t, CTX, User.GetUserId()) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("Bearer %s", token)) + sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) + require.NoError(t, err) + require.NotNil(t, id, sessionResp.GetSession().GetFactors().GetPasskey().GetVerifiedAt().AsTime()) +} + +func Test_ZITADEL_API_session_not_found(t *testing.T) { + id, token, _, _ := Tester.CreatePasskeySession(t, CTX, User.GetUserId()) + + // test session token works + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("Bearer %s", token)) + _, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) + require.NoError(t, err) + + //terminate the session and test it does not work anymore + _, err = Tester.Client.SessionV2.DeleteSession(CTX, &session.DeleteSessionRequest{ + SessionId: id, + SessionToken: gu.Ptr(token), + }) + require.NoError(t, err) + ctx = metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("Bearer %s", token)) + _, err = Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) + require.Error(t, err) +} diff --git a/internal/api/grpc/session/v2/session_test.go b/internal/api/grpc/session/v2/session_test.go index b8ae8df3a..410ab43dc 100644 --- a/internal/api/grpc/session/v2/session_test.go +++ b/internal/api/grpc/session/v2/session_test.go @@ -46,6 +46,7 @@ func Test_sessionsToPb(t *testing.T) { UserCheckedAt: past, LoginName: "donald", DisplayName: "donald duck", + ResourceOwner: "org1", }, Metadata: map[string][]byte{"hello": []byte("world")}, }, @@ -62,6 +63,7 @@ func Test_sessionsToPb(t *testing.T) { UserCheckedAt: past, LoginName: "donald", DisplayName: "donald duck", + ResourceOwner: "org1", }, PasswordFactor: query.SessionPasswordFactor{ PasswordCheckedAt: past, @@ -81,6 +83,7 @@ func Test_sessionsToPb(t *testing.T) { UserCheckedAt: past, LoginName: "donald", DisplayName: "donald duck", + ResourceOwner: "org1", }, PasskeyFactor: query.SessionPasskeyFactor{ PasskeyCheckedAt: past, @@ -105,10 +108,11 @@ func Test_sessionsToPb(t *testing.T) { Sequence: 123, Factors: &session.Factors{ User: &session.UserFactor{ - VerifiedAt: timestamppb.New(past), - Id: "345", - LoginName: "donald", - DisplayName: "donald duck", + VerifiedAt: timestamppb.New(past), + Id: "345", + LoginName: "donald", + DisplayName: "donald duck", + OrganisationId: "org1", }, }, Metadata: map[string][]byte{"hello": []byte("world")}, @@ -120,10 +124,11 @@ func Test_sessionsToPb(t *testing.T) { Sequence: 123, Factors: &session.Factors{ User: &session.UserFactor{ - VerifiedAt: timestamppb.New(past), - Id: "345", - LoginName: "donald", - DisplayName: "donald duck", + VerifiedAt: timestamppb.New(past), + Id: "345", + LoginName: "donald", + DisplayName: "donald duck", + OrganisationId: "org1", }, Password: &session.PasswordFactor{ VerifiedAt: timestamppb.New(past), @@ -138,10 +143,11 @@ func Test_sessionsToPb(t *testing.T) { Sequence: 123, Factors: &session.Factors{ User: &session.UserFactor{ - VerifiedAt: timestamppb.New(past), - Id: "345", - LoginName: "donald", - DisplayName: "donald duck", + VerifiedAt: timestamppb.New(past), + Id: "345", + LoginName: "donald", + DisplayName: "donald duck", + OrganisationId: "org1", }, Passkey: &session.PasskeyFactor{ VerifiedAt: timestamppb.New(past), diff --git a/internal/api/grpc/settings/v2/settings_converter.go b/internal/api/grpc/settings/v2/settings_converter.go index 42ba4767c..4330613d0 100644 --- a/internal/api/grpc/settings/v2/settings_converter.go +++ b/internal/api/grpc/settings/v2/settings_converter.go @@ -8,7 +8,6 @@ import ( settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha" ) -// TODO: ? func loginSettingsToPb(current *query.LoginPolicy) *settings.LoginSettings { multi := make([]settings.MultiFactorType, len(current.MultiFactors)) for i, typ := range current.MultiFactors { @@ -24,6 +23,7 @@ func loginSettingsToPb(current *query.LoginPolicy) *settings.LoginSettings { AllowRegister: current.AllowRegister, AllowExternalIdp: current.AllowExternalIDPs, ForceMfa: current.ForceMFA, + ForceMfaLocalOnly: current.ForceMFALocalOnly, PasskeysType: passkeysTypeToPb(current.PasswordlessType), HidePasswordReset: current.HidePasswordReset, IgnoreUnknownUsernames: current.IgnoreUnknownUsernames, diff --git a/internal/api/grpc/settings/v2/settings_converter_test.go b/internal/api/grpc/settings/v2/settings_converter_test.go index 11ebc0f71..e81c0a70c 100644 --- a/internal/api/grpc/settings/v2/settings_converter_test.go +++ b/internal/api/grpc/settings/v2/settings_converter_test.go @@ -25,6 +25,7 @@ func Test_loginSettingsToPb(t *testing.T) { AllowRegister: true, AllowExternalIDPs: true, ForceMFA: true, + ForceMFALocalOnly: true, PasswordlessType: domain.PasswordlessTypeAllowed, HidePasswordReset: true, IgnoreUnknownUsernames: true, @@ -52,6 +53,7 @@ func Test_loginSettingsToPb(t *testing.T) { AllowRegister: true, AllowExternalIdp: true, ForceMfa: true, + ForceMfaLocalOnly: true, PasskeysType: settings.PasskeysType_PASSKEYS_TYPE_ALLOWED, HidePasswordReset: true, IgnoreUnknownUsernames: true, diff --git a/internal/api/grpc/system/instance_converter.go b/internal/api/grpc/system/instance_converter.go index 9aeea3e2c..271dc1520 100644 --- a/internal/api/grpc/system/instance_converter.go +++ b/internal/api/grpc/system/instance_converter.go @@ -111,7 +111,7 @@ func createInstancePbToAddMachine(req *system_pb.CreateInstanceRequest_Machine, if defaultMachine.Pat != nil || req.PersonalAccessToken != nil { pat := command.AddPat{ // Scopes are currently static and can not be overwritten - Scopes: []string{oidc.ScopeOpenID, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner}, + Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner}, } if req.GetPersonalAccessToken().GetExpirationDate().IsValid() { pat.ExpirationDate = req.PersonalAccessToken.ExpirationDate.AsTime() diff --git a/internal/api/grpc/user/v2/user.go b/internal/api/grpc/user/v2/user.go index 9e28b5029..b115d83eb 100644 --- a/internal/api/grpc/user/v2/user.go +++ b/internal/api/grpc/user/v2/user.go @@ -48,10 +48,6 @@ func addUserRequestToAddHuman(req *user.AddHumanUserRequest) (*command.AddHuman, return nil, err } } - bcryptedPassword, err := hashedPasswordToCommand(req.GetHashedPassword()) - if err != nil { - return nil, err - } passwordChangeRequired := req.GetPassword().GetChangeRequired() || req.GetHashedPassword().GetChangeRequired() metadata := make([]*command.AddMetadataEntry, len(req.Metadata)) for i, metadataEntry := range req.Metadata { @@ -85,7 +81,7 @@ func addUserRequestToAddHuman(req *user.AddHumanUserRequest) (*command.AddHuman, Gender: genderToDomain(req.GetProfile().GetGender()), Phone: command.Phone{}, // TODO: add as soon as possible Password: req.GetPassword().GetPassword(), - BcryptedPassword: bcryptedPassword, + EncodedPasswordHash: req.GetHashedPassword().GetHash(), PasswordChangeRequired: passwordChangeRequired, Passwordless: false, Register: false, @@ -109,17 +105,6 @@ func genderToDomain(gender user.Gender) domain.Gender { } } -func hashedPasswordToCommand(hashed *user.HashedPassword) (string, error) { - if hashed == nil { - return "", nil - } - // we currently only handle bcrypt - if hashed.GetAlgorithm() != "bcrypt" { - return "", errors.ThrowInvalidArgument(nil, "USER-JDk4t", "Errors.InvalidArgument") - } - return hashed.GetHash(), nil -} - func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_ *user.AddIDPLinkResponse, err error) { orgID := authz.GetCtxData(ctx).OrgID details, err := s.command.AddUserIDPLink(ctx, req.UserId, orgID, &domain.UserIDPLink{ diff --git a/internal/api/grpc/user/v2/user_integration_test.go b/internal/api/grpc/user/v2/user_integration_test.go index 40efe6195..a23ebbad9 100644 --- a/internal/api/grpc/user/v2/user_integration_test.go +++ b/internal/api/grpc/user/v2/user_integration_test.go @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { Tester = integration.NewTester(ctx) defer Tester.Done() - CTX, ErrCTX = Tester.WithSystemAuthorization(ctx, integration.OrgOwner), errCtx + CTX, ErrCTX = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx Client = Tester.Client.UserV2 return m.Run() }()) @@ -392,6 +392,79 @@ func TestServer_AddHumanUser(t *testing.T) { }, }, }, + { + name: "hashed password", + args: args{ + CTX, + &user.AddHumanUserRequest{ + Organisation: &object.Organisation{ + Org: &object.Organisation_OrgId{ + OrgId: Tester.Organisation.ID, + }, + }, + Profile: &user.SetHumanProfile{ + FirstName: "Donald", + LastName: "Duck", + NickName: gu.Ptr("Dukkie"), + DisplayName: gu.Ptr("Donald Duck"), + PreferredLanguage: gu.Ptr("en"), + Gender: user.Gender_GENDER_DIVERSE.Enum(), + }, + Email: &user.SetHumanEmail{}, + Metadata: []*user.SetMetadataEntry{ + { + Key: "somekey", + Value: []byte("somevalue"), + }, + }, + PasswordType: &user.AddHumanUserRequest_HashedPassword{ + HashedPassword: &user.HashedPassword{ + Hash: "$2y$12$hXUrnqdq1RIIYZ2HPytIIe5lXdIvbhqrTvdPsSF7o.jFh817Z6lwm", + }, + }, + }, + }, + want: &user.AddHumanUserResponse{ + Details: &object.Details{ + ChangeDate: timestamppb.Now(), + ResourceOwner: Tester.Organisation.ID, + }, + }, + }, + { + name: "unsupported hashed password", + args: args{ + CTX, + &user.AddHumanUserRequest{ + Organisation: &object.Organisation{ + Org: &object.Organisation_OrgId{ + OrgId: Tester.Organisation.ID, + }, + }, + Profile: &user.SetHumanProfile{ + FirstName: "Donald", + LastName: "Duck", + NickName: gu.Ptr("Dukkie"), + DisplayName: gu.Ptr("Donald Duck"), + PreferredLanguage: gu.Ptr("en"), + Gender: user.Gender_GENDER_DIVERSE.Enum(), + }, + Email: &user.SetHumanEmail{}, + Metadata: []*user.SetMetadataEntry{ + { + Key: "somekey", + Value: []byte("somevalue"), + }, + }, + PasswordType: &user.AddHumanUserRequest_HashedPassword{ + HashedPassword: &user.HashedPassword{ + Hash: "$scrypt$ln=16,r=8,p=1$cmFuZG9tc2FsdGlzaGFyZA$Rh+NnJNo1I6nRwaNqbDm6kmADswD1+7FTKZ7Ln9D8nQ", + }, + }, + }, + }, + wantErr: true, + }, } for i, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -454,7 +527,7 @@ func TestServer_AddIDPLink(t *testing.T) { args: args{ CTX, &user.AddIDPLinkRequest{ - UserId: Tester.Users[integration.OrgOwner].ID, + UserId: Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, IdpLink: &user.IDPLink{ IdpId: "idpID", UserId: "userID", @@ -470,7 +543,7 @@ func TestServer_AddIDPLink(t *testing.T) { args: args{ CTX, &user.AddIDPLinkRequest{ - UserId: Tester.Users[integration.OrgOwner].ID, + UserId: Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, IdpLink: &user.IDPLink{ IdpId: idpID, UserId: "userID", @@ -540,7 +613,7 @@ func TestServer_StartIdentityProviderFlow(t *testing.T) { ResourceOwner: Tester.Organisation.ID, }, NextStep: &user.StartIdentityProviderFlowResponse_AuthUrl{ - AuthUrl: "https://example.com/oauth/v2/authorize?client_id=clientID&prompt=select_account&redirect_uri=https%3A%2F%2Flocalhost%3A8080%2Fidps%2Fcallback&response_type=code&scope=openid+profile+email&state=", + AuthUrl: "https://example.com/oauth/v2/authorize?client_id=clientID&prompt=select_account&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fidps%2Fcallback&response_type=code&scope=openid+profile+email&state=", }, }, wantErr: false, diff --git a/internal/api/grpc/user/v2/user_test.go b/internal/api/grpc/user/v2/user_test.go index 8332c8703..fa3ce0b0d 100644 --- a/internal/api/grpc/user/v2/user_test.go +++ b/internal/api/grpc/user/v2/user_test.go @@ -1,7 +1,6 @@ package user import ( - "errors" "testing" "time" @@ -25,74 +24,6 @@ import ( var ignoreTypes = []protoreflect.FullName{"google.protobuf.Duration", "google.protobuf.Struct"} -func Test_hashedPasswordToCommand(t *testing.T) { - type args struct { - hashed *user.HashedPassword - } - type res struct { - want string - err func(error) bool - } - tests := []struct { - name string - args args - res res - }{ - { - "not hashed", - args{ - hashed: nil, - }, - res{ - "", - nil, - }, - }, - { - "hashed, not bcrypt", - args{ - hashed: &user.HashedPassword{ - Hash: "hash", - Algorithm: "custom", - }, - }, - res{ - "", - func(err error) bool { - return errors.Is(err, caos_errs.ThrowInvalidArgument(nil, "USER-JDk4t", "Errors.InvalidArgument")) - }, - }, - }, - { - "hashed, bcrypt", - args{ - hashed: &user.HashedPassword{ - Hash: "hash", - Algorithm: "bcrypt", - }, - }, - res{ - "hash", - nil, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := hashedPasswordToCommand(tt.args.hashed) - if tt.res.err == nil { - require.NoError(t, err) - } - if tt.res.err != nil && !tt.res.err(err) { - t.Errorf("got wrong err: %v ", err) - } - if tt.res.err == nil { - assert.Equal(t, tt.res.want, got) - } - }) - } -} - func Test_intentToIDPInformationPb(t *testing.T) { decryption := func(err error) crypto.EncryptionAlgorithm { mCrypto := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t)) diff --git a/internal/api/http/cookie.go b/internal/api/http/cookie.go index ecc243e8e..18a748dc3 100644 --- a/internal/api/http/cookie.go +++ b/internal/api/http/cookie.go @@ -111,7 +111,7 @@ func (c *CookieHandler) SetCookie(w http.ResponseWriter, name, domain, value str c.httpSet(w, name, domain, value, c.maxAge) } -func (c *CookieHandler) SetEncryptedCookie(w http.ResponseWriter, name, domain string, value interface{}) error { +func (c *CookieHandler) SetEncryptedCookie(w http.ResponseWriter, name, domain string, value interface{}, sameSiteNone bool) error { if c.securecookie == nil { return errors.ThrowInternal(nil, "HTTP-s2HUtx", "securecookie not configured") } @@ -119,7 +119,11 @@ func (c *CookieHandler) SetEncryptedCookie(w http.ResponseWriter, name, domain s if err != nil { return err } - c.httpSet(w, name, domain, encoded, c.maxAge) + sameSite := c.sameSite + if sameSiteNone { + sameSite = http.SameSiteNoneMode + } + c.httpSetWithSameSite(w, name, domain, encoded, c.maxAge, sameSite) return nil } @@ -128,6 +132,10 @@ func (c *CookieHandler) DeleteCookie(w http.ResponseWriter, name string) { } func (c *CookieHandler) httpSet(w http.ResponseWriter, name, domain, value string, maxage int) { + c.httpSetWithSameSite(w, name, domain, value, maxage, c.sameSite) +} + +func (c *CookieHandler) httpSetWithSameSite(w http.ResponseWriter, name, domain, value string, maxage int, sameSite http.SameSite) { http.SetCookie(w, &http.Cookie{ Name: SetCookiePrefix(name, domain, c.path, c.secureOnly), Value: value, @@ -136,7 +144,7 @@ func (c *CookieHandler) httpSet(w http.ResponseWriter, name, domain, value strin MaxAge: maxage, HttpOnly: c.httpOnly, Secure: c.secureOnly, - SameSite: c.sameSite, + SameSite: sameSite, }) varyValues := w.Header().Values("vary") for _, vary := range varyValues { diff --git a/internal/api/http/domain_check.go b/internal/api/http/domain_check.go index b4281c778..3d3989799 100644 --- a/internal/api/http/domain_check.go +++ b/internal/api/http/domain_check.go @@ -15,7 +15,7 @@ const ( CheckTypeHTTP CheckType = iota CheckTypeDNS - HTTPPattern = "https://%s/.well-known/zitadel-challenge/%s" + HTTPPattern = "https://%s/.well-known/zitadel-challenge/%s.txt" DNSPattern = "_zitadel-challenge.%s" ) diff --git a/internal/api/http/middleware/user_agent_cookie.go b/internal/api/http/middleware/user_agent_cookie.go index 99aa482bf..36d5155f1 100644 --- a/internal/api/http/middleware/user_agent_cookie.go +++ b/internal/api/http/middleware/user_agent_cookie.go @@ -6,6 +6,9 @@ import ( "strings" "time" + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/api/authz" http_utils "github.com/zitadel/zitadel/internal/api/http" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/id" @@ -71,8 +74,11 @@ func (ua *userAgentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if err == nil { ctx := context.WithValue(r.Context(), userAgentKey, agent.ID) + instance := authz.GetInstance(r.Context()) + allowedHosts := instance.SecurityPolicyAllowedOrigins() r = r.WithContext(ctx) - ua.setUserAgent(w, r.Host, agent) + err = ua.setUserAgent(w, r.Host, agent, len(allowedHosts) > 0) + logging.WithFields("instanceID", instance.InstanceID()).OnError(err).Error("unable to set user agent cookie") } ua.nextHandler.ServeHTTP(w, r) } @@ -94,8 +100,8 @@ func (ua *userAgentHandler) getUserAgent(r *http.Request) (*UserAgent, error) { return userAgent, nil } -func (ua *userAgentHandler) setUserAgent(w http.ResponseWriter, host string, agent *UserAgent) error { - err := ua.cookieHandler.SetEncryptedCookie(w, ua.cookieName, host, agent) +func (ua *userAgentHandler) setUserAgent(w http.ResponseWriter, host string, agent *UserAgent, iframe bool) error { + err := ua.cookieHandler.SetEncryptedCookie(w, ua.cookieName, host, agent, iframe) if err != nil { return errors.ThrowPermissionDenied(err, "HTTP-AqgqdA", "cannot set user agent cookie") } diff --git a/internal/api/oidc/amr.go b/internal/api/oidc/amr.go new file mode 100644 index 000000000..727e0f888 --- /dev/null +++ b/internal/api/oidc/amr.go @@ -0,0 +1,47 @@ +package oidc + +import "github.com/zitadel/zitadel/internal/domain" + +const ( + // Password states that the users password has been verified + // Deprecated: use `PWD` instead + Password = "password" + // PWD states that the users password has been verified + PWD = "pwd" + // MFA states that multiple factors have been verified (e.g. pwd and otp or passkey) + MFA = "mfa" + // OTP states that a one time password has been verified (e.g. TOTP) + OTP = "otp" + // UserPresence states that the end users presence has been verified (e.g. passkey and u2f) + UserPresence = "user" +) + +// AuthMethodTypesToAMR maps zitadel auth method types to Authentication Method Reference Values +// as defined in [RFC 8176, section 2]. +// +// [RFC 8176, section 2]: https://datatracker.ietf.org/doc/html/rfc8176#section-2 +func AuthMethodTypesToAMR(methodTypes []domain.UserAuthMethodType) []string { + amr := make([]string, 0, 4) + var mfa bool + for _, methodType := range methodTypes { + switch methodType { + case domain.UserAuthMethodTypePassword: + amr = append(amr, PWD) + case domain.UserAuthMethodTypePasswordless: + mfa = true + amr = append(amr, UserPresence) + case domain.UserAuthMethodTypeU2F: + amr = append(amr, UserPresence) + case domain.UserAuthMethodTypeOTP: + amr = append(amr, OTP) + case domain.UserAuthMethodTypeIDP: + // no AMR value according to specification + case domain.UserAuthMethodTypeUnspecified: + // ignore + } + } + if mfa || len(amr) >= 2 { + amr = append(amr, MFA) + } + return amr +} diff --git a/internal/api/oidc/amr_test.go b/internal/api/oidc/amr_test.go new file mode 100644 index 000000000..1861085bc --- /dev/null +++ b/internal/api/oidc/amr_test.go @@ -0,0 +1,69 @@ +package oidc + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/zitadel/zitadel/internal/domain" +) + +func TestAMR(t *testing.T) { + type args struct { + methodTypes []domain.UserAuthMethodType + } + tests := []struct { + name string + args args + want []string + }{ + { + "no checks, empty", + args{ + nil, + }, + []string{}, + }, + { + "pw checked", + args{ + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + }, + []string{PWD}, + }, + { + "passkey checked", + args{ + []domain.UserAuthMethodType{domain.UserAuthMethodTypePasswordless}, + }, + []string{UserPresence, MFA}, + }, + { + "u2f checked", + args{ + []domain.UserAuthMethodType{domain.UserAuthMethodTypeU2F}, + }, + []string{UserPresence}, + }, + { + "otp checked", + args{ + []domain.UserAuthMethodType{domain.UserAuthMethodTypeOTP}, + }, + []string{OTP}, + }, + { + "multiple checked", + args{ + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword, domain.UserAuthMethodTypeU2F}, + }, + []string{PWD, UserPresence, MFA}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := AuthMethodTypesToAMR(tt.args.methodTypes) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index 0c943bfd6..4ba077d04 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -2,6 +2,7 @@ package oidc import ( "context" + "encoding/base64" "strings" "time" @@ -10,16 +11,75 @@ import ( "github.com/zitadel/oidc/v2/pkg/op" "github.com/zitadel/zitadel/internal/api/authz" + http_utils "github.com/zitadel/zitadel/internal/api/http" "github.com/zitadel/zitadel/internal/api/http/middleware" + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/user/model" ) +const ( + LoginClientHeader = "x-zitadel-login-client" +) + func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (_ op.AuthRequest, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + + headers, _ := http_utils.HeadersFromCtx(ctx) + if loginClient := headers.Get(LoginClientHeader); loginClient != "" { + return o.createAuthRequestLoginClient(ctx, req, userID, loginClient) + } + + return o.createAuthRequest(ctx, req, userID) +} + +func (o *OPStorage) createAuthRequestLoginClient(ctx context.Context, req *oidc.AuthRequest, hintUserID, loginClient string) (op.AuthRequest, error) { + project, err := o.query.ProjectByClientID(ctx, req.ClientID, false) + if err != nil { + return nil, err + } + scope, err := o.assertProjectRoleScopesByProject(ctx, project, req.Scopes) + if err != nil { + return nil, err + } + audience, err := o.audienceFromProjectID(ctx, project.ID) + if err != nil { + return nil, err + } + audience = domain.AddAudScopeToAudience(ctx, audience, scope) + authRequest := &command.AuthRequest{ + LoginClient: loginClient, + ClientID: req.ClientID, + RedirectURI: req.RedirectURI, + State: req.State, + Nonce: req.Nonce, + Scope: scope, + Audience: audience, + ResponseType: ResponseTypeToBusiness(req.ResponseType), + CodeChallenge: CodeChallengeToBusiness(req.CodeChallenge, req.CodeChallengeMethod), + Prompt: PromptToBusiness(req.Prompt), + UILocales: UILocalesToBusiness(req.UILocales), + MaxAge: MaxAgeToBusiness(req.MaxAge), + } + if req.LoginHint != "" { + authRequest.LoginHint = &req.LoginHint + } + if hintUserID != "" { + authRequest.HintUserID = &hintUserID + } + + aar, err := o.command.AddAuthRequest(ctx, authRequest) + if err != nil { + return nil, err + } + return &AuthRequestV2{aar}, nil +} + +func (o *OPStorage) createAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (_ op.AuthRequest, err error) { userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id") @@ -36,9 +96,31 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest return AuthRequestFromBusiness(resp) } +func (o *OPStorage) audienceFromProjectID(ctx context.Context, projectID string) ([]string, error) { + projectIDQuery, err := query.NewAppProjectIDSearchQuery(projectID) + if err != nil { + return nil, err + } + appIDs, err := o.query.SearchClientIDs(ctx, &query.AppSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, false) + if err != nil { + return nil, err + } + + return append(appIDs, projectID), nil +} + func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (_ op.AuthRequest, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + + if strings.HasPrefix(id, command.IDPrefixV2) { + req, err := o.command.GetCurrentAuthRequest(ctx, id) + if err != nil { + return nil, err + } + return &AuthRequestV2{req}, nil + } + userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-D3g21", "no user agent id") @@ -54,6 +136,17 @@ func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (_ op.Au ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + plainCode, err := o.decryptGrant(code) + if err != nil { + return nil, err + } + if strings.HasPrefix(plainCode, command.IDPrefixV2) { + authReq, err := o.command.ExchangeAuthCode(ctx, plainCode) + if err != nil { + return nil, err + } + return &AuthRequestV2{authReq}, nil + } resp, err := o.repo.AuthRequestByCode(ctx, code) if err != nil { return nil, err @@ -61,9 +154,23 @@ func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (_ op.Au return AuthRequestFromBusiness(resp) } +// decryptGrant decrypts a code or refresh_token +func (o *OPStorage) decryptGrant(grant string) (string, error) { + decodedGrant, err := base64.RawURLEncoding.DecodeString(grant) + if err != nil { + return "", err + } + return o.encAlg.DecryptString(decodedGrant, o.encAlg.EncryptionKeyID()) +} + func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + + if strings.HasPrefix(id, command.IDPrefixV2) { + return o.command.AddAuthRequestCode(ctx, id, code) + } + userAgentID, ok := middleware.UserAgentIDFromCtx(ctx) if !ok { return errors.ThrowPreconditionFailed(nil, "OIDC-Dgus2", "no user agent id") @@ -81,12 +188,15 @@ func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) (err error func (o *OPStorage) CreateAccessToken(ctx context.Context, req op.TokenRequest) (_ string, _ time.Time, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + var userAgentID, applicationID, userOrgID string - authReq, ok := req.(*AuthRequest) - if ok { + switch authReq := req.(type) { + case *AuthRequest: userAgentID = authReq.AgentID applicationID = authReq.ApplicationID userOrgID = authReq.UserOrgID + case *AuthRequestV2: + return o.command.AddOIDCSessionAccessToken(setContextUserSystem(ctx), authReq.GetID()) } accessTokenLifetime, _, _, _, err := o.getOIDCSettings(ctx) @@ -104,6 +214,15 @@ func (o *OPStorage) CreateAccessToken(ctx context.Context, req op.TokenRequest) func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.TokenRequest, refreshToken string) (_, _ string, _ time.Time, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + + // handle V2 request directly + switch tokenReq := req.(type) { + case *AuthRequestV2: + return o.command.AddOIDCSessionRefreshAndAccessToken(setContextUserSystem(ctx), tokenReq.GetID()) + case *RefreshTokenRequestV2: + return o.command.ExchangeOIDCSessionRefreshAndAccessToken(setContextUserSystem(ctx), tokenReq.OIDCSessionWriteModel.AggregateID, refreshToken, tokenReq.RequestedScopes) + } + userAgentID, applicationID, userOrgID, authTime, authMethodsReferences := getInfoFromRequest(req) scopes, err := o.assertProjectRoleScopes(ctx, applicationID, req.GetScopes()) if err != nil { @@ -142,7 +261,22 @@ func getInfoFromRequest(req op.TokenRequest) (string, string, string, time.Time, return "", "", "", time.Time{}, nil } -func (o *OPStorage) TokenRequestByRefreshToken(ctx context.Context, refreshToken string) (op.RefreshTokenRequest, error) { +func (o *OPStorage) TokenRequestByRefreshToken(ctx context.Context, refreshToken string) (_ op.RefreshTokenRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + plainToken, err := o.decryptGrant(refreshToken) + if err != nil { + return nil, err + } + if strings.HasPrefix(plainToken, command.IDPrefixV2) { + oidcSession, err := o.command.OIDCSessionByRefreshToken(ctx, plainToken) + if err != nil { + return nil, err + } + return &RefreshTokenRequestV2{OIDCSessionWriteModel: oidcSession}, nil + } + tokenView, err := o.repo.RefreshTokenByToken(ctx, refreshToken) if err != nil { return nil, err @@ -174,7 +308,56 @@ func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID strin return err } -func (o *OPStorage) RevokeToken(ctx context.Context, token, userID, clientID string) *oidc.Error { +func (o *OPStorage) TerminateSessionFromRequest(ctx context.Context, endSessionRequest *op.EndSessionRequest) (redirectURI string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + // check for the login client header + // and if not provided, terminate the session using the V1 method + headers, _ := http_utils.HeadersFromCtx(ctx) + if loginClient := headers.Get(LoginClientHeader); loginClient == "" { + return endSessionRequest.RedirectURI, o.TerminateSession(ctx, endSessionRequest.UserID, endSessionRequest.ClientID) + } + + // in case there are not id_token_hint, redirect to the UI and let it decide which session to terminate + if endSessionRequest.IDTokenHintClaims == nil { + return o.defaultLogoutURLV2 + endSessionRequest.RedirectURI, nil + } + + // terminate the session of the id_token_hint + _, err = o.command.TerminateSessionWithoutTokenCheck(ctx, endSessionRequest.IDTokenHintClaims.SessionID) + if err != nil { + return "", err + } + return endSessionRequest.RedirectURI, nil +} + +func (o *OPStorage) RevokeToken(ctx context.Context, token, userID, clientID string) (err *oidc.Error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { + // check for nil, because `err` is not an error and EndWithError would panic + if err == nil { + span.End() + return + } + span.EndWithError(err) + }() + + if strings.HasPrefix(token, command.IDPrefixV2) { + err := o.command.RevokeOIDCSessionToken(ctx, token, clientID) + if err == nil { + return nil + } + if errors.IsPreconditionFailed(err) { + return oidc.ErrInvalidClient().WithDescription("token was not issued for this client") + } + return oidc.ErrServerError().WithParent(err) + } + + return o.revokeTokenV1(ctx, token, userID, clientID) +} + +func (o *OPStorage) revokeTokenV1(ctx context.Context, token, userID, clientID string) *oidc.Error { refreshToken, err := o.repo.RefreshTokenByID(ctx, token, userID) if err == nil { if refreshToken.ClientID != clientID { @@ -204,6 +387,17 @@ func (o *OPStorage) RevokeToken(ctx context.Context, token, userID, clientID str } func (o *OPStorage) GetRefreshTokenInfo(ctx context.Context, clientID string, token string) (userID string, tokenID string, err error) { + plainToken, err := o.decryptGrant(token) + if err != nil { + return "", "", op.ErrInvalidRefreshToken + } + if strings.HasPrefix(plainToken, command.IDPrefixV2) { + oidcSession, err := o.command.OIDCSessionByRefreshToken(ctx, plainToken) + if err != nil { + return "", "", op.ErrInvalidRefreshToken + } + return oidcSession.UserID, oidcSession.OIDCRefreshTokenID(oidcSession.RefreshTokenID), nil + } refreshToken, err := o.repo.RefreshTokenByToken(ctx, token) if err != nil { return "", "", op.ErrInvalidRefreshToken @@ -245,6 +439,29 @@ func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string return scopes, nil } +func (o *OPStorage) assertProjectRoleScopesByProject(ctx context.Context, project *query.Project, scopes []string) ([]string, error) { + for _, scope := range scopes { + if strings.HasPrefix(scope, ScopeProjectRolePrefix) { + return scopes, nil + } + } + if !project.ProjectRoleAssertion { + return scopes, nil + } + projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(project.ID) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal") + } + roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, false) + if err != nil { + return nil, err + } + for _, role := range roles.ProjectRoles { + scopes = append(scopes, ScopeProjectRolePrefix+role.Key) + } + return scopes, nil +} + func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.TokenView, clientID, projectID string) error { token.Audience = append(token.Audience, clientID) projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(projectID) @@ -279,3 +496,58 @@ func (o *OPStorage) getOIDCSettings(ctx context.Context) (accessTokenLifetime, i } return o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime, o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, nil } + +func CreateErrorCallbackURL(authReq op.AuthRequest, reason, description, uri string, authorizer op.Authorizer) (string, error) { + e := struct { + Error string `schema:"error"` + Description string `schema:"error_description,omitempty"` + URI string `schema:"error_uri,omitempty"` + State string `schema:"state,omitempty"` + }{ + Error: reason, + Description: description, + URI: uri, + State: authReq.GetState(), + } + callback, err := op.AuthResponseURL(authReq.GetRedirectURI(), authReq.GetResponseType(), authReq.GetResponseMode(), e, authorizer.Encoder()) + if err != nil { + return "", err + } + return callback, nil +} + +func CreateCodeCallbackURL(ctx context.Context, authReq op.AuthRequest, authorizer op.Authorizer) (string, error) { + code, err := op.CreateAuthRequestCode(ctx, authReq, authorizer.Storage(), authorizer.Crypto()) + if err != nil { + return "", err + } + codeResponse := struct { + code string + state string + }{ + code: code, + state: authReq.GetState(), + } + callback, err := op.AuthResponseURL(authReq.GetRedirectURI(), authReq.GetResponseType(), authReq.GetResponseMode(), &codeResponse, authorizer.Encoder()) + if err != nil { + return "", err + } + return callback, err +} + +func CreateTokenCallbackURL(ctx context.Context, req op.AuthRequest, authorizer op.Authorizer) (string, error) { + client, err := authorizer.Storage().GetClientByClientID(ctx, req.GetClientID()) + if err != nil { + return "", err + } + createAccessToken := req.GetResponseType() != oidc.ResponseTypeIDTokenOnly + resp, err := op.CreateTokenResponse(ctx, req, client, authorizer, createAccessToken, "", "") + if err != nil { + return "", err + } + callback, err := op.AuthResponseURL(req.GetRedirectURI(), req.GetResponseType(), req.GetResponseMode(), resp, authorizer.Encoder()) + if err != nil { + return "", err + } + return callback, err +} diff --git a/internal/api/oidc/auth_request_converter.go b/internal/api/oidc/auth_request_converter.go index 647346084..02cbf8cba 100644 --- a/internal/api/oidc/auth_request_converter.go +++ b/internal/api/oidc/auth_request_converter.go @@ -17,15 +17,6 @@ import ( "github.com/zitadel/zitadel/internal/user/model" ) -const ( - // DEPRECATED: use `amrPWD` instead - amrPassword = "password" - amrPWD = "pwd" - amrMFA = "mfa" - amrOTP = "otp" - amrUserPresence = "user" -) - type AuthRequest struct { *domain.AuthRequest } @@ -40,19 +31,19 @@ func (a *AuthRequest) GetACR() string { } func (a *AuthRequest) GetAMR() []string { - amr := make([]string, 0) + list := make([]string, 0) if a.PasswordVerified { - amr = append(amr, amrPassword, amrPWD) + list = append(list, Password, PWD) } if len(a.MFAsVerified) > 0 { - amr = append(amr, amrMFA) + list = append(list, MFA) for _, mfa := range a.MFAsVerified { if amrMFA := AMRFromMFAType(mfa); amrMFA != "" { - amr = append(amr, amrMFA) + list = append(list, amrMFA) } } } - return amr + return list } func (a *AuthRequest) GetAudience() []string { @@ -271,10 +262,10 @@ func CodeChallengeToOIDC(challenge *domain.OIDCCodeChallenge) *oidc.CodeChalleng func AMRFromMFAType(mfaType domain.MFAType) string { switch mfaType { case domain.MFATypeOTP: - return amrOTP + return OTP case domain.MFATypeU2F, domain.MFATypeU2FUserVerification: - return amrUserPresence + return UserPresence default: return "" } diff --git a/internal/api/oidc/auth_request_converter_v2.go b/internal/api/oidc/auth_request_converter_v2.go new file mode 100644 index 000000000..9f4c0d0a1 --- /dev/null +++ b/internal/api/oidc/auth_request_converter_v2.go @@ -0,0 +1,106 @@ +package oidc + +import ( + "time" + + "github.com/zitadel/oidc/v2/pkg/oidc" + + "github.com/zitadel/zitadel/internal/command" +) + +type AuthRequestV2 struct { + *command.CurrentAuthRequest +} + +func (a *AuthRequestV2) GetID() string { + return a.ID +} + +func (a *AuthRequestV2) GetACR() string { + return "" //PLANNED: impl +} + +func (a *AuthRequestV2) GetAMR() []string { + return AuthMethodTypesToAMR(a.AuthMethods) +} + +func (a *AuthRequestV2) GetAudience() []string { + return a.Audience +} + +func (a *AuthRequestV2) GetAuthTime() time.Time { + return a.AuthTime +} + +func (a *AuthRequestV2) GetClientID() string { + return a.ClientID +} + +func (a *AuthRequestV2) GetCodeChallenge() *oidc.CodeChallenge { + return CodeChallengeToOIDC(a.CodeChallenge) +} + +func (a *AuthRequestV2) GetNonce() string { + return a.Nonce +} + +func (a *AuthRequestV2) GetRedirectURI() string { + return a.RedirectURI +} + +func (a *AuthRequestV2) GetResponseType() oidc.ResponseType { + return ResponseTypeToOIDC(a.ResponseType) +} + +func (a *AuthRequestV2) GetResponseMode() oidc.ResponseMode { + return "" +} + +func (a *AuthRequestV2) GetScopes() []string { + return a.Scope +} + +func (a *AuthRequestV2) GetState() string { + return a.State +} + +func (a *AuthRequestV2) GetSubject() string { + return a.UserID +} + +func (a *AuthRequestV2) Done() bool { + return a.UserID != "" && a.SessionID != "" +} + +type RefreshTokenRequestV2 struct { + *command.OIDCSessionWriteModel + RequestedScopes []string +} + +func (r *RefreshTokenRequestV2) GetAMR() []string { + return AuthMethodTypesToAMR(r.AuthMethods) +} + +func (r *RefreshTokenRequestV2) GetAudience() []string { + return r.Audience +} + +func (r *RefreshTokenRequestV2) GetAuthTime() time.Time { + return r.AuthTime +} + +func (r *RefreshTokenRequestV2) GetClientID() string { + return r.ClientID +} + +func (r *RefreshTokenRequestV2) GetScopes() []string { + return r.Scope +} + +func (r *RefreshTokenRequestV2) GetSubject() string { + return r.UserID +} + +func (r *RefreshTokenRequestV2) SetCurrentScopes(scopes []string) { + r.RequestedScopes = scopes +} diff --git a/internal/api/oidc/auth_request_integration_test.go b/internal/api/oidc/auth_request_integration_test.go new file mode 100644 index 000000000..7651b32c8 --- /dev/null +++ b/internal/api/oidc/auth_request_integration_test.go @@ -0,0 +1,550 @@ +//go:build integration + +package oidc_test + +import ( + "context" + "net/url" + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitadel/oidc/v2/pkg/client/rp" + "github.com/zitadel/oidc/v2/pkg/oidc" + + http_utils "github.com/zitadel/zitadel/internal/api/http" + oidc_api "github.com/zitadel/zitadel/internal/api/oidc" + "github.com/zitadel/zitadel/internal/command" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" + session "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha" +) + +var ( + armPasskey = []string{oidc_api.UserPresence, oidc_api.MFA} + armPassword = []string{oidc_api.PWD} +) + +func TestOPStorage_CreateAuthRequest(t *testing.T) { + clientID := createClient(t) + + id := createAuthRequest(t, clientID, redirectURI) + require.Contains(t, id, command.IDPrefixV2) +} + +func TestOPStorage_CreateAccessToken_code(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // test code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, false) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // callback on a succeeded request must fail + linkResp, err = Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.Error(t, err) + + // exchange with a used code must fail + _, err = exchangeTokens(t, clientID, code) + require.Error(t, err) +} + +func TestOPStorage_CreateAccessToken_implicit(t *testing.T) { + clientID := createImplicitClient(t) + authRequestID := createAuthRequestImplicit(t, clientID, redirectURIImplicit) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // test implicit callback + callback, err := url.Parse(linkResp.GetCallbackUrl()) + require.NoError(t, err) + values, err := url.ParseQuery(callback.Fragment) + require.NoError(t, err) + accessToken := values.Get("access_token") + idToken := values.Get("id_token") + refreshToken := values.Get("refresh_token") + assert.NotEmpty(t, accessToken) + assert.NotEmpty(t, idToken) + assert.Empty(t, refreshToken) + assert.NotEmpty(t, values.Get("expires_in")) + assert.Equal(t, oidc.BearerToken, values.Get("token_type")) + assert.Equal(t, "state", values.Get("state")) + + // check id_token / claims + provider, err := Tester.CreateRelyingParty(clientID, redirectURIImplicit) + require.NoError(t, err) + claims, err := rp.VerifyTokens[*oidc.IDTokenClaims](context.Background(), accessToken, idToken, provider.IDTokenVerifier()) + require.NoError(t, err) + assertIDTokenClaims(t, claims, armPasskey, startTime, changeTime) + + // callback on a succeeded request must fail + linkResp, err = Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.Error(t, err) +} + +func TestOPStorage_CreateAccessAndRefreshTokens_code(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // test code exchange (expect refresh token to be returned) + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) +} + +func TestOPStorage_CreateAccessAndRefreshTokens_refresh(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // test actual refresh grant + newTokens, err := refreshTokens(t, clientID, tokens.RefreshToken) + require.NoError(t, err) + assertTokens(t, newTokens, true) + // auth time must still be the initial + assertIDTokenClaims(t, newTokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // refresh with an old refresh_token must fail + _, err = rp.RefreshAccessToken(provider, tokens.RefreshToken, "", "") + require.Error(t, err) +} + +func TestOPStorage_RevokeToken_access_token(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // revoke access token + err = rp.RevokeToken(provider, tokens.AccessToken, "access_token") + require.NoError(t, err) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) + + // refresh grant must still work + _, err = refreshTokens(t, clientID, tokens.RefreshToken) + require.NoError(t, err) + + // revocation with the same access token must not fail (with or without hint) + err = rp.RevokeToken(provider, tokens.AccessToken, "access_token") + require.NoError(t, err) + err = rp.RevokeToken(provider, tokens.AccessToken, "") + require.NoError(t, err) +} + +func TestOPStorage_RevokeToken_access_token_invalid_token_hint_type(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // revoke access token + err = rp.RevokeToken(provider, tokens.AccessToken, "refresh_token") + require.NoError(t, err) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) + + // refresh grant must still work + _, err = refreshTokens(t, clientID, tokens.RefreshToken) + require.NoError(t, err) +} + +func TestOPStorage_RevokeToken_refresh_token(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // revoke refresh token -> invalidates also access token + err = rp.RevokeToken(provider, tokens.RefreshToken, "refresh_token") + require.NoError(t, err) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) + + // refresh must fail + _, err = refreshTokens(t, clientID, tokens.RefreshToken) + require.Error(t, err) + + // revocation with the same refresh token must not fail (with or without hint) + err = rp.RevokeToken(provider, tokens.RefreshToken, "refresh_token") + require.NoError(t, err) + err = rp.RevokeToken(provider, tokens.RefreshToken, "") + require.NoError(t, err) +} + +func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // revoke refresh token even with a wrong hint + err = rp.RevokeToken(provider, tokens.RefreshToken, "access_token") + require.NoError(t, err) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) + + // refresh must fail + _, err = refreshTokens(t, clientID, tokens.RefreshToken) + require.Error(t, err) +} + +func TestOPStorage_RevokeToken_invalid_client(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // simulate second client (not part of the audience) trying to revoke the token + otherClientID := createClient(t) + provider, err := Tester.CreateRelyingParty(otherClientID, redirectURI) + require.NoError(t, err) + err = rp.RevokeToken(provider, tokens.AccessToken, "") + require.Error(t, err) +} + +func TestOPStorage_TerminateSession(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // test code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, false) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // userinfo must not fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.NoError(t, err) + + postLogoutRedirect, err := rp.EndSession(provider, tokens.IDToken, logoutRedirectURI, "state") + require.NoError(t, err) + assert.Equal(t, logoutRedirectURI+"?state=state", postLogoutRedirect.String()) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) +} + +func TestOPStorage_TerminateSession_refresh_grant(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // test code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // userinfo must not fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.NoError(t, err) + + postLogoutRedirect, err := rp.EndSession(provider, tokens.IDToken, logoutRedirectURI, "state") + require.NoError(t, err) + assert.Equal(t, logoutRedirectURI+"?state=state", postLogoutRedirect.String()) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) + + refreshedTokens, err := refreshTokens(t, clientID, tokens.RefreshToken) + require.NoError(t, err) + + // userinfo must not fail + _, err = rp.Userinfo(refreshedTokens.AccessToken, refreshedTokens.TokenType, refreshedTokens.IDTokenClaims.Subject, provider) + require.NoError(t, err) +} + +func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // test code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, false) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + postLogoutRedirect, err := rp.EndSession(provider, "", logoutRedirectURI, "state") + require.NoError(t, err) + assert.Equal(t, http_utils.BuildOrigin(Tester.Host(), Tester.Config.ExternalSecure)+Tester.Config.OIDC.DefaultLogoutURLV2+logoutRedirectURI+"?state=state", postLogoutRedirect.String()) + + // userinfo must not fail until login UI terminated session + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.NoError(t, err) + + // simulate termination by login UI + _, err = Tester.Client.SessionV2.DeleteSession(CTXLOGIN, &session.DeleteSessionRequest{ + SessionId: sessionID, + SessionToken: gu.Ptr(sessionToken), + }) + require.NoError(t, err) + + // userinfo must fail + _, err = rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.Error(t, err) +} + +func exchangeTokens(t testing.TB, clientID, code string) (*oidc.Tokens[*oidc.IDTokenClaims], error) { + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + + codeVerifier := "codeVerifier" + return rp.CodeExchange[*oidc.IDTokenClaims](context.Background(), code, provider, rp.WithCodeVerifier(codeVerifier)) +} + +func refreshTokens(t testing.TB, clientID, refreshToken string) (*oidc.Tokens[*oidc.IDTokenClaims], error) { + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + + tokens, err := rp.RefreshAccessToken(provider, refreshToken, "", "") + if err != nil { + return nil, err + } + idToken, _ := tokens.Extra("id_token").(string) + claims, err := rp.VerifyTokens[*oidc.IDTokenClaims](context.Background(), tokens.AccessToken, idToken, provider.IDTokenVerifier()) + if err != nil { + return nil, err + } + return &oidc.Tokens[*oidc.IDTokenClaims]{ + Token: tokens, + IDToken: idToken, + IDTokenClaims: claims, + }, nil +} + +func assertCodeResponse(t *testing.T, callback string) string { + callbackURL, err := url.Parse(callback) + require.NoError(t, err) + code := callbackURL.Query().Get("code") + require.NotEmpty(t, code) + assert.Equal(t, "state", callbackURL.Query().Get("state")) + return code +} + +func assertTokens(t *testing.T, tokens *oidc.Tokens[*oidc.IDTokenClaims], requireRefreshToken bool) { + assert.NotEmpty(t, tokens.AccessToken) + assert.NotEmpty(t, tokens.IDToken) + if requireRefreshToken { + assert.NotEmpty(t, tokens.RefreshToken) + } else { + assert.Empty(t, tokens.RefreshToken) + } +} + +func assertIDTokenClaims(t *testing.T, claims *oidc.IDTokenClaims, arm []string, sessionStart, sessionChange time.Time) { + assert.Equal(t, User.GetUserId(), claims.Subject) + assert.Equal(t, arm, claims.AuthenticationMethodsReferences) + assertOIDCTimeRange(t, claims.AuthTime, sessionStart, sessionChange) +} diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go index e1a26f866..7a418df9a 100644 --- a/internal/api/oidc/client.go +++ b/internal/api/oidc/client.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "strings" + "time" "github.com/dop251/goja" "github.com/zitadel/logging" @@ -17,6 +18,7 @@ import ( "github.com/zitadel/zitadel/internal/actions/object" "github.com/zitadel/zitadel/internal/api/authz" api_http "github.com/zitadel/zitadel/internal/api/http" + "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" @@ -66,7 +68,7 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Cl return nil, err } - return ClientFromBusiness(client, o.defaultLoginURL, accessTokenLifetime, idTokenLifetime, allowedScopes) + return ClientFromBusiness(client, o.defaultLoginURL, o.defaultLoginURLV2, accessTokenLifetime, idTokenLifetime, allowedScopes) } func (o *OPStorage) GetKeyByIDAndClientID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) { @@ -119,18 +121,26 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo *oidc.UserInfo, tokenID, subject, origin string) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + + if strings.HasPrefix(tokenID, command.IDPrefixV2) { + token, err := o.query.ActiveAccessTokenByToken(ctx, tokenID) + if err != nil { + return err + } + if err = o.isOriginAllowed(ctx, token.ClientID, origin); err != nil { + return err + } + return o.setUserinfo(ctx, userInfo, token.UserID, token.ClientID, token.Scope, nil) + } + token, err := o.repo.TokenByIDs(ctx, subject, tokenID) if err != nil { return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired") } if token.ApplicationID != "" { - app, err := o.query.AppByOIDCClientID(ctx, token.ApplicationID, false) - if err != nil { + if err = o.isOriginAllowed(ctx, token.ApplicationID, origin); err != nil { return err } - if origin != "" && !api_http.IsOriginAllowed(app.OIDCConfig.AllowedOrigins, origin) { - return errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed") - } } return o.setUserinfo(ctx, userInfo, token.UserID, token.ApplicationID, token.Scopes, nil) } @@ -153,7 +163,37 @@ func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo *oidc.Us return o.setUserinfo(ctx, userInfo, userID, applicationID, scopes, nil) } -func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection *oidc.IntrospectionResponse, tokenID, subject, clientID string) error { +// SetUserinfoFromRequest extends the SetUserinfoFromScopes during the id_token generation. +// This is required for V2 tokens to be able to set the sessionID (`sid`) claim. +func (o *OPStorage) SetUserinfoFromRequest(ctx context.Context, userinfo *oidc.UserInfo, request op.IDTokenRequest, _ []string) error { + switch t := request.(type) { + case *AuthRequestV2: + userinfo.AppendClaims("sid", t.SessionID) + case *RefreshTokenRequestV2: + userinfo.AppendClaims("sid", t.SessionID) + } + return nil +} + +func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection *oidc.IntrospectionResponse, tokenID, subject, clientID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + if strings.HasPrefix(tokenID, command.IDPrefixV2) { + token, err := o.query.ActiveAccessTokenByToken(ctx, tokenID) + if err != nil { + return err + } + projectID, err := o.query.ProjectIDFromClientID(ctx, clientID, false) + if err != nil { + return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found") + } + return o.introspect(ctx, introspection, + tokenID, token.UserID, token.ClientID, projectID, + token.Audience, token.Scope, + token.AccessTokenCreation, token.AccessTokenExpiration) + } + token, err := o.repo.TokenByIDs(ctx, subject, tokenID) if err != nil { return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired") @@ -168,27 +208,10 @@ func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection return errors.ThrowPreconditionFailed(err, "OIDC-AGefw", "Errors.Internal") } } - for _, aud := range token.Audience { - if aud == clientID || aud == projectID { - userInfo := new(oidc.UserInfo) - err := o.setUserinfo(ctx, userInfo, subject, clientID, token.Scopes, []string{projectID}) // always - if err != nil { - return err - } - introspection.SetUserInfo(userInfo) - introspection.Scope = token.Scopes - introspection.ClientID = token.ApplicationID - introspection.TokenType = oidc.BearerToken - introspection.Expiration = oidc.FromTime(token.Expiration) - introspection.IssuedAt = oidc.FromTime(token.CreationDate) - introspection.NotBefore = oidc.FromTime(token.CreationDate) - introspection.Audience = token.Audience - introspection.Issuer = op.IssuerFromContext(ctx) - introspection.JWTID = token.ID - return nil - } - } - return errors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client") + return o.introspect(ctx, introspection, + token.ID, token.UserID, token.ApplicationID, projectID, + token.Audience, token.Scopes, + token.CreationDate, token.Expiration) } func (o *OPStorage) ClientCredentialsTokenRequest(ctx context.Context, clientID string, scope []string) (op.TokenRequest, error) { @@ -230,6 +253,55 @@ func (o *OPStorage) ClientCredentials(ctx context.Context, clientID, clientSecre }, nil } +// isOriginAllowed checks whether a call by the client to the endpoint is allowed from the provided origin +// if no origin is provided, no error will be returned +func (o *OPStorage) isOriginAllowed(ctx context.Context, clientID, origin string) error { + if origin == "" { + return nil + } + app, err := o.query.AppByOIDCClientID(ctx, clientID, false) + if err != nil { + return err + } + if api_http.IsOriginAllowed(app.OIDCConfig.AllowedOrigins, origin) { + return nil + } + return errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed") +} + +func (o *OPStorage) introspect( + ctx context.Context, + introspection *oidc.IntrospectionResponse, + tokenID, subject, clientID, projectID string, + audience, scope []string, + tokenCreation, tokenExpiration time.Time, +) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + for _, aud := range audience { + if aud == clientID || aud == projectID { + userInfo := new(oidc.UserInfo) + err = o.setUserinfo(ctx, userInfo, subject, clientID, scope, []string{projectID}) // always + if err != nil { + return err + } + introspection.SetUserInfo(userInfo) + introspection.Scope = scope + introspection.ClientID = clientID + introspection.TokenType = oidc.BearerToken + introspection.Expiration = oidc.FromTime(tokenExpiration) + introspection.IssuedAt = oidc.FromTime(tokenCreation) + introspection.NotBefore = oidc.FromTime(tokenCreation) + introspection.Audience = audience + introspection.Issuer = op.IssuerFromContext(ctx) + introspection.JWTID = tokenID + return nil + } + } + return errors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client") +} + func (o *OPStorage) checkOrgScopes(ctx context.Context, user *query.User, scopes []string) ([]string, error) { for i := len(scopes) - 1; i >= 0; i-- { scope := scopes[i] diff --git a/internal/api/oidc/client_converter.go b/internal/api/oidc/client_converter.go index 6b32f3892..5f3f25f75 100644 --- a/internal/api/oidc/client_converter.go +++ b/internal/api/oidc/client_converter.go @@ -7,6 +7,7 @@ import ( "github.com/zitadel/oidc/v2/pkg/oidc" "github.com/zitadel/oidc/v2/pkg/op" + "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/query" @@ -15,18 +16,20 @@ import ( type Client struct { app *query.App defaultLoginURL string + defaultLoginURLV2 string defaultAccessTokenLifetime time.Duration defaultIdTokenLifetime time.Duration allowedScopes []string } -func ClientFromBusiness(app *query.App, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration, allowedScopes []string) (op.Client, error) { +func ClientFromBusiness(app *query.App, defaultLoginURL, defaultLoginURLV2 string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration, allowedScopes []string) (op.Client, error) { if app.OIDCConfig == nil { return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application") } return &Client{ app: app, defaultLoginURL: defaultLoginURL, + defaultLoginURLV2: defaultLoginURLV2, defaultAccessTokenLifetime: defaultAccessTokenLifetime, defaultIdTokenLifetime: defaultIdTokenLifetime, allowedScopes: allowedScopes}, @@ -46,6 +49,9 @@ func (c *Client) GetID() string { } func (c *Client) LoginURL(id string) string { + if strings.HasPrefix(id, command.IDPrefixV2) { + return c.defaultLoginURLV2 + id + } return c.defaultLoginURL + id } diff --git a/internal/api/oidc/client_integration_test.go b/internal/api/oidc/client_integration_test.go new file mode 100644 index 000000000..513f25a75 --- /dev/null +++ b/internal/api/oidc/client_integration_test.go @@ -0,0 +1,135 @@ +//go:build integration + +package oidc_test + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitadel/oidc/v2/pkg/client/rp" + "github.com/zitadel/oidc/v2/pkg/client/rs" + "github.com/zitadel/oidc/v2/pkg/oidc" + + "github.com/zitadel/zitadel/pkg/grpc/authn" + "github.com/zitadel/zitadel/pkg/grpc/management" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" +) + +func TestOPStorage_SetUserinfoFromToken(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // test actual userinfo + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + userinfo, err := rp.Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider) + require.NoError(t, err) + assertUserinfo(t, userinfo) +} + +func TestOPStorage_SetIntrospectionFromToken(t *testing.T) { + project, err := Tester.CreateProject(CTX) + require.NoError(t, err) + app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + require.NoError(t, err) + api, err := Tester.CreateAPIClient(CTX, project.GetId()) + require.NoError(t, err) + keyResp, err := Tester.Client.Mgmt.AddAppKey(CTX, &management.AddAppKeyRequest{ + ProjectId: project.GetId(), + AppId: api.GetAppId(), + Type: authn.KeyType_KEY_TYPE_JSON, + ExpirationDate: nil, + }) + require.NoError(t, err) + resourceServer, err := Tester.CreateResourceServer(keyResp.GetKeyDetails()) + require.NoError(t, err) + + scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess} + authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, app.GetClientId(), code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // test actual introspection + introspection, err := rs.Introspect(context.Background(), resourceServer, tokens.AccessToken) + require.NoError(t, err) + assertIntrospection(t, introspection, + Tester.OIDCIssuer(), app.GetClientId(), + scope, []string{app.GetClientId(), api.GetClientId(), project.GetId()}, + tokens.Expiry, tokens.Expiry.Add(-12*time.Hour)) +} + +func assertUserinfo(t *testing.T, userinfo *oidc.UserInfo) { + assert.Equal(t, User.GetUserId(), userinfo.Subject) + assert.Equal(t, "Mickey", userinfo.GivenName) + assert.Equal(t, "Mouse", userinfo.FamilyName) + assert.Equal(t, "Mickey Mouse", userinfo.Name) + assert.NotEmpty(t, userinfo.PreferredUsername) + assert.Equal(t, userinfo.PreferredUsername, userinfo.Email) + assert.False(t, bool(userinfo.EmailVerified)) + assertOIDCTime(t, userinfo.UpdatedAt, User.GetDetails().GetChangeDate().AsTime()) +} + +func assertIntrospection( + t *testing.T, + introspection *oidc.IntrospectionResponse, + issuer, clientID string, + scope, audience []string, + expiration, creation time.Time, +) { + assert.True(t, introspection.Active) + assert.Equal(t, scope, []string(introspection.Scope)) + assert.Equal(t, clientID, introspection.ClientID) + assert.Equal(t, oidc.BearerToken, introspection.TokenType) + assertOIDCTime(t, introspection.Expiration, expiration) + assertOIDCTime(t, introspection.IssuedAt, creation) + assertOIDCTime(t, introspection.NotBefore, creation) + assert.Equal(t, User.GetUserId(), introspection.Subject) + assert.ElementsMatch(t, audience, introspection.Audience) + assert.Equal(t, issuer, introspection.Issuer) + assert.NotEmpty(t, introspection.JWTID) + assert.NotEmpty(t, introspection.Username) + assert.Equal(t, introspection.Username, introspection.PreferredUsername) + assert.Equal(t, "Mickey", introspection.GivenName) + assert.Equal(t, "Mouse", introspection.FamilyName) + assert.Equal(t, "Mickey Mouse", introspection.Name) + assert.Equal(t, introspection.Username, introspection.Email) + assert.False(t, bool(introspection.EmailVerified)) + assertOIDCTime(t, introspection.UpdatedAt, User.GetDetails().GetChangeDate().AsTime()) +} diff --git a/internal/api/oidc/oidc_integration_test.go b/internal/api/oidc/oidc_integration_test.go new file mode 100644 index 000000000..da34b30d7 --- /dev/null +++ b/internal/api/oidc/oidc_integration_test.go @@ -0,0 +1,292 @@ +//go:build integration + +package oidc_test + +import ( + "context" + "fmt" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitadel/oidc/v2/pkg/client/rp" + "github.com/zitadel/oidc/v2/pkg/oidc" + "google.golang.org/grpc/metadata" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/integration" + "github.com/zitadel/zitadel/pkg/grpc/auth" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" + session "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha" + user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha" +) + +var ( + CTX context.Context + CTXLOGIN context.Context + Tester *integration.Tester + User *user.AddHumanUserResponse +) + +const ( + redirectURI = "oidcintegrationtest://callback" + redirectURIImplicit = "http://localhost:9999/callback" + logoutRedirectURI = "oidcintegrationtest://logged-out" + zitadelAudienceScope = domain.ProjectIDScope + domain.ProjectIDScopeZITADEL + domain.AudSuffix +) + +func TestMain(m *testing.M) { + os.Exit(func() int { + ctx, errCtx, cancel := integration.Contexts(5 * time.Minute) + defer cancel() + + Tester = integration.NewTester(ctx) + defer Tester.Done() + + CTX, _ = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx + User = Tester.CreateHumanUser(CTX) + Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword) + Tester.RegisterUserPasskey(CTX, User.GetUserId()) + CTXLOGIN, _ = Tester.WithAuthorization(ctx, integration.Login), errCtx + return m.Run() + }()) +} + +func Test_ZITADEL_API_missing_audience_scope(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, false) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.Error(t, err) + require.Nil(t, myUserResp) +} + +func Test_ZITADEL_API_missing_authentication(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope) + createResp, err := Tester.Client.SessionV2.CreateSession(CTX, &session.CreateSessionRequest{ + Checks: &session.Checks{ + User: &session.CheckUser{ + Search: &session.CheckUser_UserId{UserId: User.GetUserId()}, + }, + }, + Domain: Tester.Config.ExternalDomain, + }) + require.NoError(t, err) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: createResp.GetSessionId(), + SessionToken: createResp.GetSessionToken(), + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.Error(t, err) + require.Nil(t, myUserResp) +} + +func Test_ZITADEL_API_missing_mfa(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasswordSession(t, CTX, User.GetUserId(), integration.UserPassword) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPassword, startTime, changeTime) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.Error(t, err) + require.Nil(t, myUserResp) +} + +func Test_ZITADEL_API_success(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, false) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.NoError(t, err) + require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId()) +} + +func Test_ZITADEL_API_inactive_access_token(t *testing.T) { + clientID := createClient(t) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // make sure token works + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.NoError(t, err) + require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId()) + + // refresh token + newTokens, err := refreshTokens(t, clientID, tokens.RefreshToken) + require.NoError(t, err) + assert.NotEmpty(t, newTokens.AccessToken) + + // use invalidated token + ctx = metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + myUserResp, err = Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.Error(t, err) + require.Nil(t, myUserResp) +} + +func Test_ZITADEL_API_terminated_session(t *testing.T) { + clientID := createClient(t) + provider, err := Tester.CreateRelyingParty(clientID, redirectURI) + require.NoError(t, err) + authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope) + sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ + AuthRequestId: authRequestID, + CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ + Session: &oidc_pb.Session{ + SessionId: sessionID, + SessionToken: sessionToken, + }, + }, + }) + require.NoError(t, err) + + // code exchange + code := assertCodeResponse(t, linkResp.GetCallbackUrl()) + tokens, err := exchangeTokens(t, clientID, code) + require.NoError(t, err) + assertTokens(t, tokens, true) + assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime) + + // make sure token works + ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.NoError(t, err) + require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId()) + + // refresh token + postLogoutRedirect, err := rp.EndSession(provider, tokens.IDToken, logoutRedirectURI, "state") + require.NoError(t, err) + assert.Equal(t, logoutRedirectURI+"?state=state", postLogoutRedirect.String()) + + // use token from terminated session + ctx = metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken)) + myUserResp, err = Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{}) + require.Error(t, err) + require.Nil(t, myUserResp) +} + +func createClient(t testing.TB) string { + project, err := Tester.CreateProject(CTX) + require.NoError(t, err) + app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId()) + require.NoError(t, err) + return app.GetClientId() +} + +func createImplicitClient(t testing.TB) string { + app, err := Tester.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit) + require.NoError(t, err) + return app.GetClientId() +} + +func createAuthRequest(t testing.TB, clientID, redirectURI string, scope ...string) string { + redURL, err := Tester.CreateOIDCAuthRequest(clientID, Tester.Users[integration.FirstInstanceUsersKey][integration.Login].ID, redirectURI, scope...) + require.NoError(t, err) + return redURL +} + +func createAuthRequestImplicit(t testing.TB, clientID, redirectURI string, scope ...string) string { + redURL, err := Tester.CreateOIDCAuthRequestImplicit(clientID, Tester.Users[integration.FirstInstanceUsersKey][integration.Login].ID, redirectURI, scope...) + require.NoError(t, err) + return redURL +} + +func assertOIDCTime(t *testing.T, actual oidc.Time, expected time.Time) { + assertOIDCTimeRange(t, actual, expected, expected) +} + +func assertOIDCTimeRange(t *testing.T, actual oidc.Time, expectedStart, expectedEnd time.Time) { + assert.WithinRange(t, actual.AsTime(), expectedStart.Add(-1*time.Second), expectedEnd.Add(1*time.Second)) +} diff --git a/internal/api/oidc/op.go b/internal/api/oidc/op.go index 9574f561b..62dad091e 100644 --- a/internal/api/oidc/op.go +++ b/internal/api/oidc/op.go @@ -41,6 +41,8 @@ type Config struct { Cache *middleware.CacheConfig CustomEndpoints *EndpointConfig DeviceAuth *DeviceAuthorizationConfig + DefaultLoginURLV2 string + DefaultLogoutURLV2 string } type EndpointConfig struct { @@ -65,6 +67,8 @@ type OPStorage struct { query *query.Queries eventstore *eventstore.Eventstore defaultLoginURL string + defaultLoginURLV2 string + defaultLogoutURLV2 string defaultAccessTokenLifetime time.Duration defaultIdTokenLifetime time.Duration signingKeyAlgorithm string @@ -181,6 +185,8 @@ func newStorage(config Config, command *command.Commands, query *query.Queries, query: query, eventstore: es, defaultLoginURL: fmt.Sprintf("%s%s?%s=", login.HandlerPrefix, login.EndpointLogin, login.QueryAuthRequestID), + defaultLoginURLV2: config.DefaultLoginURLV2, + defaultLogoutURLV2: config.DefaultLogoutURLV2, signingKeyAlgorithm: config.SigningKeyAlgorithm, defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime, defaultIdTokenLifetime: config.DefaultIdTokenLifetime, diff --git a/internal/api/ui/console/console.go b/internal/api/ui/console/console.go index 320d753b4..7e00605b7 100644 --- a/internal/api/ui/console/console.go +++ b/internal/api/ui/console/console.go @@ -34,7 +34,7 @@ type spaHandler struct { } var ( - //go:embed static/* + //go:embed static static embed.FS ) diff --git a/internal/api/ui/console/static/.gitkeep b/internal/api/ui/console/static/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/.artifacts/zitadel/.gitkeep b/internal/api/ui/console/static/gitkeep similarity index 100% rename from .artifacts/zitadel/.gitkeep rename to internal/api/ui/console/static/gitkeep diff --git a/internal/api/ui/login/external_provider_handler.go b/internal/api/ui/login/external_provider_handler.go index 38029ad05..ee7696cc4 100644 --- a/internal/api/ui/login/external_provider_handler.go +++ b/internal/api/ui/login/external_provider_handler.go @@ -897,6 +897,10 @@ func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserG } func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens[*oidc.IDTokenClaims], user idp.User, err error) { + if authReq == nil { + l.renderLogin(w, r, authReq, err) + return + } if _, _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens, authReq, r, user, err); actionErr != nil { logging.WithError(err).Error("both external user authentication and action post authentication failed") } diff --git a/internal/api/ui/login/static/i18n/bg.yaml b/internal/api/ui/login/static/i18n/bg.yaml index 2c4ca6666..20b1c1084 100644 --- a/internal/api/ui/login/static/i18n/bg.yaml +++ b/internal/api/ui/login/static/i18n/bg.yaml @@ -221,6 +221,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: Пол Female: Женски пол Male: Мъжки @@ -253,6 +255,7 @@ ExternalRegistrationUserOverview: Japanese: 日本語 Polish: Полски Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Правила и условия TosConfirm: Приемам TosLinkText: TOS @@ -309,6 +312,8 @@ ExternalNotFound: Polish: Полски Japanese: 日本語 Spanish: Español + Macedonian: Македонски + DeviceAuth: Title: Упълномощаване на устройството UserCode: diff --git a/internal/api/ui/login/static/i18n/de.yaml b/internal/api/ui/login/static/i18n/de.yaml index ca8c6cf58..984580359 100644 --- a/internal/api/ui/login/static/i18n/de.yaml +++ b/internal/api/ui/login/static/i18n/de.yaml @@ -223,6 +223,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: Geschlecht Female: weiblich Male: männlich @@ -256,6 +258,7 @@ ExternalRegistrationUserOverview: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz TosConfirm: Ich akzeptiere die TosLinkText: AGBs @@ -317,7 +320,8 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español - + Macedonian: Македонски + DeviceAuth: Title: Geräteautorisierung UserCode: diff --git a/internal/api/ui/login/static/i18n/en.yaml b/internal/api/ui/login/static/i18n/en.yaml index 83862ee5f..ceb60654e 100644 --- a/internal/api/ui/login/static/i18n/en.yaml +++ b/internal/api/ui/login/static/i18n/en.yaml @@ -211,8 +211,8 @@ RegistrationUser: DescriptionOrgRegister: Enter your Userdata. EmailLabel: E-Mail UsernameLabel: Username - FirstnameLabel: First name - LastnameLabel: Surname + FirstnameLabel: Given name + LastnameLabel: Family name LanguageLabel: Language German: Deutsch English: English @@ -222,6 +222,8 @@ RegistrationUser: Polish: Polski Japanese: 日本語 Spanish: Español + Portuguese: Português + Macedonian: Македонски GenderLabel: Gender Female: Female Male: Male @@ -242,8 +244,8 @@ ExternalRegistrationUserOverview: Description: We have taken your user details from the selected provider. You can now change or complete them. EmailLabel: E-Mail UsernameLabel: Username - FirstnameLabel: First name - LastnameLabel: Surname + FirstnameLabel: Given name + LastnameLabel: Family name NicknameLabel: Nickname PhoneLabel: Phonenumber LanguageLabel: Language @@ -255,6 +257,7 @@ ExternalRegistrationUserOverview: Japanese: 日本語 Polish: Polski Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Terms and conditions TosConfirm: I accept the TosLinkText: TOS @@ -270,8 +273,8 @@ RegistrationOrg: OrgNameLabel: Organization name EmailLabel: E-Mail UsernameLabel: Username - FirstnameLabel: First name - LastnameLabel: Surname + FirstnameLabel: Given name + LastnameLabel: Family name PasswordLabel: Password PasswordConfirmLabel: Password confirmation TosAndPrivacyLabel: Terms and conditions @@ -317,6 +320,8 @@ ExternalNotFound: Japanese: 日本語 Spanish: Español Bulgarian: Български + Macedonian: Македонски + DeviceAuth: Title: Device Authorization UserCode: @@ -366,8 +371,8 @@ Errors: NotFound: Profile not found NotChanged: Profile not changed Empty: Profile is empty - FirstNameEmpty: First name in profile is empty - LastNameEmpty: Last name in profile is empty + FirstNameEmpty: Given name in profile is empty + LastNameEmpty: Family name in profile is empty IDMissing: Profile ID is missing Email: NotFound: Email not found diff --git a/internal/api/ui/login/static/i18n/es.yaml b/internal/api/ui/login/static/i18n/es.yaml index e92cda9f1..7adf48d53 100644 --- a/internal/api/ui/login/static/i18n/es.yaml +++ b/internal/api/ui/login/static/i18n/es.yaml @@ -223,6 +223,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: Género Female: Mujer Male: Hombre @@ -256,6 +258,7 @@ ExternalRegistrationUserOverview: Japanese: 日本語 Polish: Polski Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Términos y condiciones TosConfirm: Acepto los TosLinkText: TDS @@ -317,7 +320,8 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español - + Macedonian: Македонски + Footer: PoweredBy: Powered By Tos: TDS diff --git a/internal/api/ui/login/static/i18n/fr.yaml b/internal/api/ui/login/static/i18n/fr.yaml index b963c5837..7cd2b0ad8 100644 --- a/internal/api/ui/login/static/i18n/fr.yaml +++ b/internal/api/ui/login/static/i18n/fr.yaml @@ -223,6 +223,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: Genre Female: Femme Male: Homme @@ -256,6 +258,7 @@ ExternalRegistrationUserOverview: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Termes et conditions TosConfirm: J'accepte les TosLinkText: TOS @@ -317,6 +320,7 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски DeviceAuth: Title: Autorisation de l'appareil diff --git a/internal/api/ui/login/static/i18n/it.yaml b/internal/api/ui/login/static/i18n/it.yaml index 6073342e2..8a30e9f97 100644 --- a/internal/api/ui/login/static/i18n/it.yaml +++ b/internal/api/ui/login/static/i18n/it.yaml @@ -223,6 +223,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: Genere Female: Femminile Male: Maschile @@ -256,6 +258,7 @@ ExternalRegistrationUserOverview: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Termini di servizio TosConfirm: Accetto i TosLinkText: Termini di servizio @@ -317,6 +320,7 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски DeviceAuth: Title: Autorizzazione del dispositivo diff --git a/internal/api/ui/login/static/i18n/ja.yaml b/internal/api/ui/login/static/i18n/ja.yaml index a5028e9e5..599710131 100644 --- a/internal/api/ui/login/static/i18n/ja.yaml +++ b/internal/api/ui/login/static/i18n/ja.yaml @@ -215,6 +215,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: 性別 Female: 女性 Male: 男性 @@ -248,6 +250,7 @@ ExternalRegistrationUserOverview: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: 利用規約 TosConfirm: 私は利用規約を承諾します。 TosLinkText: TOS @@ -309,6 +312,7 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски DeviceAuth: Title: デバイス認証 diff --git a/internal/api/ui/login/static/i18n/mk.yaml b/internal/api/ui/login/static/i18n/mk.yaml new file mode 100644 index 000000000..d17f2fdbb --- /dev/null +++ b/internal/api/ui/login/static/i18n/mk.yaml @@ -0,0 +1,456 @@ +Login: + Title: Добредојдовте назад! + Description: Внесете ги вашите податоци за најава. + TitleLinking: Најава за поврзување на корисник + DescriptionLinking: Внесете ги вашите податоци за најава за да го поврзете вашиот надворешен корисник со корисник на ZITADEL. + LoginNameLabel: Корисничко име за најава + UsernamePlaceHolder: корисничко име + LoginnamePlaceHolder: username@domain + ExternalUserDescription: Најава со надворешен корисник. + MustBeMemberOfOrg: Корисникот мора да биде член на организацијата {{.OrgName}}. + RegisterButtonText: регистрирај се + NextButtonText: следно + +LDAP: + Title: Најава + Description: Внесете ги вашите податоци за најава. + LoginNameLabel: Корисничко име за најава + PasswordLabel: Лозинка + NextButtonText: следно + +SelectAccount: + Title: Изберете корисничка сметка + Description: Користете ја вашата ZITADEL корисничка сметка + TitleLinking: Изберете корисничка сметка за поврзување на корисник + DescriptionLinking: Изберете ја вашата корисничка сметка за да ја поврзете со вашиот надворешен корисник. + OtherUser: Друг корисник + SessionState0: активна + SessionState1: неактивна + MustBeMemberOfOrg: Корисникот мора да биде член на организацијата {{.OrgName}}. + +Password: + Title: Лозинка + Description: Внесете ги вашите податоци за најава. + PasswordLabel: Лозинка + MinLength: Минимална должина + HasUppercase: Голема буква + HasLowercase: Мала буква + HasNumber: Број + HasSymbol: Симбол + Confirmation: Потврда на лозинка + ResetLinkText: ресетирај лозинка + BackButtonText: назад + NextButtonText: следно + +UsernameChange: + Title: Промена на корисничко име + Description: Поставете го вашето ново корисничко име + UsernameLabel: Корисничко име + CancelButtonText: откажи + NextButtonText: следно + +UsernameChangeDone: + Title: Корисничкото име е променето + Description: Вашето корисничко име е успешно променето. + NextButtonText: следно + +InitPassword: + Title: Поставете лозинка + Description: Добивте код кој треба да го внесете во формата подолу за да поставите нова лозинка. + CodeLabel: Код + NewPasswordLabel: Нова лозинка + NewPasswordConfirmLabel: Потврда на лозинка + ResendButtonText: повторно испрати код + NextButtonText: следно + +InitPasswordDone: + Title: Лозинката е поставена + Description: Лозинката е успешно поставена. + NextButtonText: следно + CancelButtonText: откажи + +InitUser: + Title: Активирајте корисник + Description: Проверете ја вашата е-пошта со кодот подолу и поставете ја вашата лозинка. + CodeLabel: Код + NewPasswordLabel: Нова лозинка + NewPasswordConfirm: Потврда на лозинка + NextButtonText: следно + ResendButtonText: повторно испрати код + +InitUserDone: + Title: Корисникот е активиран + Description: Е-поштата е верифицирана и лозинката е успешно поставена. + NextButtonText: следно + CancelButtonText: откажи + +InitMFAPrompt: + Title: Подесување на 2-факторска автентикација + Description: 2-факторската автентикација ви дава дополнителна безбедност за вашата корисничка сметка. Ова обезбедува само вие да имате пристап до вашата сметка. + Provider0: Апликација за автентикација (на пример Google/Microsoft Authenticator, Authy) + Provider1: Во зависност од вашиот уред (на пример FaceID, Windows Hello, отпечаток од прст) + NextButtonText: следно + SkipButtonText: прескокни + +InitMFAOTP: + Title: Потврда на 2-факторска автентикација + Description: Креирајте ја вашата 2-факторска автентикација. Превземете апликација за автентикација доколку сѐ уште немате една. + OTPDescription: Скенирајте го кодот со вашата апликација за автентикација (на пример Google/Microsoft Authenticator, Authy) или копирајте го тајниот клуч и вметнете го генерираниот код подолу. + SecretLabel: Таен клуч + CodeLabel: Код + NextButtonText: следно + CancelButtonText: откажи + +InitMFAU2F: + Title: Додајте безбедносен клуч + Description: Безбедносниот клуч е метод на верификација кој може да се интегрира во вашиот телефон, да користи Bluetooth или директно да се поврзе во USB приклучокот на вашиот компјутер. + TokenNameLabel: Име на безбедносниот клуч / уред + NotSupported: WebAuthN не е поддржан од вашиот прелистувач. Ве молиме проверете дали е ажуриран со најновата верзија или пак користете друг прелистувач (на пример Chrome, Safari, Firefox) + RegisterTokenButtonText: Додајте безбедносен клуч + ErrorRetry: Обидете се повторно, креирајте нов предизвик или изберете друг метод. + +InitMFADone: + Title: Потврден безбедносен клуч + Description: Одлично! Успешно ја подесивте вашата 2-факторска автентикација и ја зголемивте безбедноста на вашата корисничка сметка. Факторот мора да се користи при секоја најава. + NextButtonText: следно + CancelButtonText: откажи + +MFAProvider: + Provider0: Апликација за автентикација (на пример Google/Microsoft Authenticator, Authy) + Provider1: Во зависност од вашиот уред (на пример FaceID, Windows Hello, отпечаток од прст) + ChooseOther: или изберете друга опција + +VerifyMFAOTP: + Title: Потврда на 2-факторска автентикација + Description: Потврдете ја 2-факторска автентикација + CodeLabel: Код + NextButtonText: следно + +VerifyMFAU2F: + Title: Потврда на 2-факторска автентикација + Description: Потврдете ја вашата 2-факторска автентикација со регистрираниот уред (на пример FaceID, Windows Hello, отпечаток од прст) + NotSupported: WebAuthN не е поддржан од вашиот прелистувач. Ве молиме проверете дали е ажуриран со најновата верзија или пак користете друг прелистувач (Chrome, Safari, Firefox) + ErrorRetry: Обидете се повторно, креирајте нов барање или изберете друг метод. + ValidateTokenButtonText: Потврди 2-факторска автентикација + +Passwordless: + Title: Најава без лозинка + Description: Најавете се со методи за автентикација кои ги нуди вашиот уред, како FaceID, Windows Hello или отпечаток од прст. + NotSupported: WebAuthN не е поддржан од вашиот прелистувач. Ве молиме проверете дали е ажуриран со најновата верзија или пак користете друг прелистувач (на пример Chrome, Safari, Firefox) + ErrorRetry: Обидете се повторно, креирајте нов предизвик или изберете друг метод. + LoginWithPwButtonText: Најава со лозинка + ValidateTokenButtonText: Најава без лозинка + +PasswordlessPrompt: + Title: Подесување на најава без лозинка + Description: Дали сакате да подесите најава без лозинка? (Методи за автентикација на вашиот уред, како FaceID, Windows Hello или отпечаток од прст) + DescriptionInit: Мора да подесите најава без лозинка. Користете го линкот што ви беше даден за регистрација на вашиот уред. + PasswordlessButtonText: Отиди на најава без лозинка + NextButtonText: следно + SkipButtonText: прескокни + +PasswordlessRegistration: + Title: Подесување на најава без лозинка + Description: Додадете ја вашата автентикација со давање на име (на пример, МојМобиленТелефон, MacBook итн) и кликнете на копчето 'Регистрирај најава без лозинка' подолу. + TokenNameLabel: Име на уредот + NotSupported: WebAuthN не е поддржан од вашиот прелистувач. Ве молиме проверете дали е ажуриран со најновата верзија или пак користете друг прелистувач (на пример, Chrome, Safari, Firefox) + RegisterTokenButtonText: Регистрирај најава без лозинка + ErrorRetry: Обидете се повторно, креирајте нов предизвик или изберете друг метод. + +PasswordlessRegistrationDone: + Title: Подесена најава без лозинка + Description: Уредот за најава без лозинка е успешно додаден. + DescriptionClose: Сега можете да го затворите овој прозорец. + NextButtonText: следно + CancelButtonText: откажи + +PasswordChange: + Title: Промена на лозинка + Description: Променете ја вашата лозинка. Внесете ја старата и новата лозинка. + OldPasswordLabel: Стара лозинка + NewPasswordLabel: Нова лозинка + NewPasswordConfirmLabel: Потврда на лозинка + CancelButtonText: откажи + NextButtonText: следно + Footer: Футер + +PasswordChangeDone: + Title: Промена на лозинка + Description: Вашата лозинка беше успешно променета. + NextButtonText: следно + +PasswordResetDone: + Title: Пратен линк за ресетирање на лозинка + Description: Проверете ја вашата е-пошта за ресетирање на лозинката. + NextButtonText: следно + +EmailVerification: + Title: Верификација на е-пошта + Description: Ви пративме е-пошта за да ја верификувате вашата адреса за е-пошта. Ве молиме внесете го кодот во формата подолу. + CodeLabel: Код + NextButtonText: следно + ResendButtonText: испрати повторно + +EmailVerificationDone: + Title: Верификација на е-пошта + Description: Вашата е-пошта беше успешно верифицирана. + NextButtonText: следно + CancelButtonText: откажи + LoginButtonText: најава + +RegisterOption: + Title: Опции за регистрација + Description: Изберете како сакате да се регистрирате + RegisterUsernamePasswordButtonText: Со корисничко име и лозинка + ExternalLoginDescription: или регистрирајте се со надворешен корисник + LoginButtonText: најава + +RegistrationUser: + Title: Регистрација + Description: Внесете ги вашите кориснички податоци. Вашата е-пошта ќе се користи како корисничко име. + DescriptionOrgRegister: Внесете ги вашите кориснички податоци. + EmailLabel: Е-пошта + UsernameLabel: Корисничко име + FirstnameLabel: Име + LastnameLabel: Презиме + LanguageLabel: Јазик + German: Deutsch + English: English + Italian: Italiano + French: Français + Chinese: 简体中文 + Polish: Polski + Japanese: 日本語 + Spanish: Español + Portuguese: Português + Macedonian: Македонски + GenderLabel: Пол + Female: Женски + Male: Машки + Diverse: различен / X + PasswordLabel: Лозинка + PasswordConfirmLabel: Потврда на лозинка + TosAndPrivacyLabel: Правила и услови + TosConfirm: Се согласувам со + TosLinkText: правилата за користење + PrivacyConfirm: Се согласувам со + PrivacyLinkText: политиката за приватност + ExternalLogin: или регистрирајте се со надворешен корисник + BackButtonText: најава + NextButtonText: следно + +ExternalRegistrationUserOverview: + Title: Регистрација на надворешен корисник + Description: Ги преземаме вашите податоци за корисник од избраниот провајдер. Сега можете да ги промените или дополните. + EmailLabel: Е-пошта + UsernameLabel: Корисничко име + FirstnameLabel: Име + LastnameLabel: Презиме + NicknameLabel: Прекар + PhoneLabel: Телефонски број + LanguageLabel: Јазик + German: Deutsch + English: English + Italian: Italiano + French: Français + Chinese: 简体中文 + Japanese: 日本語 + Polish: Polski + Spanish: Español + Portuguese: Português + Macedonian: Македонски + TosAndPrivacyLabel: Правила и услови + TosConfirm: Се согласувам со + TosLinkText: правилата за користење + PrivacyConfirm: Се согласувам со + PrivacyLinkText: политиката за приватност + ExternalLogin: или регистрирајте се со надворешен корисник + BackButtonText: назад + NextButtonText: зачувај + +RegistrationOrg: + Title: Регистрација на организација + Description: Внесете го името и податоците на вашата организација. + OrgNameLabel: Име на организација + EmailLabel: Е-пошта + UsernameLabel: Корисничко име + FirstnameLabel: Име + LastnameLabel: Презиме + PasswordLabel: Лозинка + PasswordConfirmLabel: Потврда на лозинка + TosAndPrivacyLabel: Правила и услови + TosConfirm: Се согласувам со + TosLinkText: правилата за користење + PrivacyConfirm: Се согласувам со + PrivacyLinkText: политиката за приватност + SaveButtonText: Креирај организација + +LoginSuccess: + Title: Успешна најава + AutoRedirectDescription: Ќе бидете автоматски пренасочени назад кон вашата апликација. Доколку не сте автоматски пренасочени, кликнете на копчето подолу. Потоа можете да го затворите прозорецот. + RedirectedDescription: Сега можете да го затворите овој прозорец. + NextButtonText: следно + +LogoutDone: + Title: Одјавени + Description: Успешно сте одјавени. + LoginButtonText: најава + +LinkingUsersDone: + Title: Поврзување на корисници + Description: Поврзувањето на корисници е завршено. + CancelButtonText: откажи + NextButtonText: следно + +ExternalNotFound: + Title: Не е пронајден надворешен корисник + Description: Надворешниот корисник не е пронајден. Дали сакате да го поврзете вашиот корисник или автоматски да регистрирате нов. + LinkButtonText: Поврзи + AutoRegisterButtonText: регистрирај + TosAndPrivacyLabel: Правила и услови + TosConfirm: Се согласувам со + TosLinkText: правилата за користење + PrivacyConfirm: Се согласувам со + PrivacyLinkText: политиката за приватност + German: Deutsch + English: English + Italian: Italiano + French: Français + Chinese: 简体中文 + Polish: Polski + Japanese: 日本語 + Spanish: Español + Bulgarian: Български + Portuguese: Português + Macedonian: Македонски + +DeviceAuth: + Title: Овластување преку уред + UserCode: + Label: Код на корисник + Description: Внесете го кодот на корисникот прикажан на уредот. + ButtonNext: следно + Action: + Description: Овластување за пристап за уред. + GrantDevice: со ова ќе овозможите уредот да има право за + AccessToScopes: пристап до следниве области + Button: + Allow: овозможи + Deny: одбиј + Done: + Description: Завршено. + Approved: Овластувањето на уредот е одобрено. Сега можете да се вратите на уредот. + Denied: Овластувањето на уредот е одбиено. Сега можете да се вратите на уредот. + +Footer: + PoweredBy: Поддржано од + Tos: Услови за користење + PrivacyPolicy: Политика за приватност + Help: Помош + SupportEmail: Е-пошта за поддршка + +Errors: + Internal: Се појави внатрешна грешка + AuthRequest: + NotFound: Не може да се пронајде барањето за автентикација + UserAgentNotCorresponding: User Agent не се совпаѓа + UserAgentNotFound: Не е пронајден User Agent ID + TokenNotFound: Токенот не е пронајден + RequestTypeNotSupported: Типот на барање не е подржан + MissingParameters: Недостасуваат задолжителни параметри + User: + NotFound: Корисникот не е пронајден + AlreadyExists: Корисникот веќе постои + Inactive: Корисникот е неактивен + NotFoundOnOrg: Корисникот не е пронајден во избраната организација + NotAllowedOrg: Корисникот не е член на бараната организација + NotMatchingUserID: Корисникот и корисникот во барањето за автентикација не се совпаѓаат + UserIDMissing: ID на корисник е празно + Invalid: Невалидни кориснички податоци + DomainNotAllowedAsUsername: Доменот е веќе резервиран и не може да се користи + NotAllowedToLink: Корисникот нема дозвола да се поврзе со надворешен провајдер за најава + Profile: + NotFound: Профилот не е пронајден + NotChanged: Профилот не е променет + Empty: Профилот е празен + FirstNameEmpty: Името во профилот е празно + LastNameEmpty: Презимето во профилот е празно + IDMissing: ID на профил е празно + Email: + NotFound: Е-поштата не е пронајдена + Invalid: Е-поштата не е валидна + AlreadyVerified: Е-поштата веќе е верифицирана + NotChanged: Е-поштата не е променета + Empty: Е-поштата е празна + IDMissing: ID на е-пошта е празно + Phone: + NotFound: Телефонскиот број не е пронајден + Invalid: Телефонскиот број не е валиден + AlreadyVerified: Телефонскиот број е веќе верифициран + Empty: Телефонскиот број е празен + NotChanged: Телефонскиот број не е променет + Address: + NotFound: Адресата не е пронајдена + NotChanged: Адресата не е променета + Username: + AlreadyExists: Корисничкото име е веќе зафатено + Reserved: Корисничкото име е веќе зафатено + Empty: Корисничкото име е празно + Password: + ConfirmationWrong: Потврдата на лозинката не е точна + Empty: Лозинката е празна + Invalid: Лозинката не е валидна + InvalidAndLocked: Лозинката не е валидна и корисникот е заклучен, контактирајте со вашиот администратор. + UsernameOrPassword: + Invalid: Корисничкото име и/или лозинката не се валидни + PasswordComplexityPolicy: + NotFound: Политиката за сложеност на лозинката не е пронајдена + MinLength: Лозинката е прекратка + HasLower: Лозинката мора да содржи мала буква + HasUpper: Лозинката мора да содржи голема буква + HasNumber: Лозинката мора да содржи број + HasSymbol: Лозинката мора да содржи симбол + Code: + Expired: Кодот е истечен + Invalid: Кодот не е валиден + Empty: Кодот е празен + CryptoCodeNil: Крипто кодот е nil + NotFound: Кодот не е пронајден + GeneratorAlgNotSupported: Неподдржан алгоритам на генераторот + EmailVerify: + UserIDEmpty: ID на корисник е празно + ExternalData: + CouldNotRead: Надворешните податоци не можеа да се прочитаат точно + MFA: + NoProviders: Нема достапни провајдери за мултифакторна автентикација + OTP: + AlreadyReady: Мултифактор OTP (Еднократна Лозинка) е веќе подесена + NotExisting: Мултифактор OTP (Еднократна Лозинка) не постои + InvalidCode: Невалиден код + NotReady: Мултифактор OTP (Еднократна Лозинка) не е подготвена + Locked: Корисникот е заклучен + SomethingWentWrong: Се случи нешто неочекувано + NotActive: Корисникот не е активен + ExternalIDP: + IDPTypeNotImplemented: Типот на идентитетски надворешен провајдер не е имплементиран + NotAllowed: Надворешниот идентитетски провајдер за најава не е дозволен + IDPConfigIDEmpty: ID на надворешниот идентитетски провајдер е празно + ExternalUserIDEmpty: ID на надворешниот корисник е празно + UserDisplayNameEmpty: Приказното име на корисникот е празно + NoExternalUserData: Нема преземени податоци за надворешен корисник + CreationNotAllowed: Креирањето на нов корисник не е дозволено на овој провајдер + LinkingNotAllowed: Поврзувањето на корисник не е дозволено на овој провајдер + GrantRequired: Не е можно најавување. Корисникот мора да има барем едно овластување за апликацијата. Ве молиме контактирајте го вашиот администратор. + ProjectRequired: Не е можно најавување. Организацијата на корисникот мора да биде доделена на проектот. Ве молиме контактирајте го вашиот администратор. + IdentityProvider: + InvalidConfig: Конфигурацијата на идентитетскиот провајдер не е валидна + IAM: + LockoutPolicy: + NotExisting: Политиката за заклучување не постои + Org: + LoginPolicy: + RegistrationNotAllowed: Не е дозволена регистрација + DeviceAuth: + NotExisting: Кодот на корисникот не постои + +optional: (опционално) diff --git a/internal/api/ui/login/static/i18n/pl.yaml b/internal/api/ui/login/static/i18n/pl.yaml index 12b4b2e24..56d4cc683 100644 --- a/internal/api/ui/login/static/i18n/pl.yaml +++ b/internal/api/ui/login/static/i18n/pl.yaml @@ -223,6 +223,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: Płeć Female: Kobieta Male: Mężczyzna @@ -256,6 +258,7 @@ ExternalRegistrationUserOverview: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: Warunki i zasady TosConfirm: Akceptuję TosLinkText: Warunki korzystania @@ -317,6 +320,7 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски DeviceAuth: Title: Autoryzacja urządzenia diff --git a/internal/api/ui/login/static/i18n/pt.yaml b/internal/api/ui/login/static/i18n/pt.yaml new file mode 100644 index 000000000..e887ff6bc --- /dev/null +++ b/internal/api/ui/login/static/i18n/pt.yaml @@ -0,0 +1,452 @@ +Login: + Title: Bem-vindo de volta! + Description: Insira seus dados de login. + TitleLinking: Login para vinculação de usuário + DescriptionLinking: Insira seus dados de login para vincular seu usuário externo a um usuário do ZITADEL. + LoginNameLabel: Nome de login + UsernamePlaceHolder: nome de usuário + LoginnamePlaceHolder: nome de usuário@domínio + ExternalUserDescription: Faça login com um usuário externo. + MustBeMemberOfOrg: O usuário deve ser membro da organização {{.OrgName}}. + RegisterButtonText: registrar + NextButtonText: próximo + +LDAP: + Title: Login + Description: Insira seus dados de login. + LoginNameLabel: Nome de login + PasswordLabel: Senha + NextButtonText: próximo + +SelectAccount: + Title: Selecionar conta + Description: Use sua conta ZITADEL + TitleLinking: Selecionar conta para vinculação de usuário + DescriptionLinking: Selecione sua conta para vincular com seu usuário externo. + OtherUser: Outro usuário + SessionState0: ativo + SessionState1: inativo + MustBeMemberOfOrg: O usuário deve ser membro da organização {{.OrgName}}. + +Password: + Title: Senha + Description: Insira seus dados de login. + PasswordLabel: Senha + MinLength: Comprimento mínimo + HasUppercase: Letra maiúscula + HasLowercase: Letra minúscula + HasNumber: Número + HasSymbol: Símbolo + Confirmation: Confirmação corresponde + ResetLinkText: redefinir senha + BackButtonText: voltar + NextButtonText: próximo + +UsernameChange: + Title: Alterar nome de usuário + Description: Defina seu novo nome de usuário + UsernameLabel: Nome de usuário + CancelButtonText: cancelar + NextButtonText: próximo + +UsernameChangeDone: + Title: Nome de usuário alterado + Description: Seu nome de usuário foi alterado com sucesso. + NextButtonText: próximo + +InitPassword: + Title: Definir senha + Description: Você recebeu um código, que deve inserir no formulário abaixo para definir sua nova senha. + CodeLabel: Código + NewPasswordLabel: Nova senha + NewPasswordConfirmLabel: Confirmar senha + ResendButtonText: reenviar código + NextButtonText: próximo + +InitPasswordDone: + Title: Senha definida + Description: Senha definida com sucesso + NextButtonText: próximo + CancelButtonText: cancelar + +InitUser: + Title: Ativar usuário + Description: Verifique seu e-mail com o código abaixo e defina sua senha. + CodeLabel: Código + NewPasswordLabel: Nova senha + NewPasswordConfirm: Confirmar senha + NextButtonText: próximo + ResendButtonText: reenviar código + +InitUserDone: + Title: Usuário ativado + Description: E-mail verificado e senha definida com sucesso + NextButtonText: próximo + CancelButtonText: cancelar + +InitMFAPrompt: + Title: Configuração de 2 fatores + Description: A autenticação de 2 fatores fornece uma segurança adicional para sua conta de usuário. Isso garante que apenas você tenha acesso à sua conta. + Provider0: Aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy) + Provider1: Dependente do dispositivo (por exemplo, FaceID, Windows Hello, Impressão digital) + NextButtonText: próximo + SkipButtonText: pular + +InitMFAOTP: + Title: Verificação de 2 fatores + Description: Crie sua verificação de 2 fatores. Faça o download de um aplicativo de autenticação se ainda não tiver um. + OTPDescription: Digitalize o código com seu aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy) ou copie o segredo e insira o código gerado abaixo. + SecretLabel: Segredo + CodeLabel: Código + NextButtonText: próximo + CancelButtonText: cancelar + +InitMFAU2F: + Title: Adicionar chave de segurança + Description: Uma chave de segurança é um método de verificação que pode ser incorporado ao seu telefone, usar Bluetooth ou conectar diretamente à porta USB do seu computador. + TokenNameLabel: Nome da chave de segurança / dispositivo + NotSupported: WebAuthN não é suportado pelo seu navegador. Verifique se ele está atualizado ou use outro navegador (por exemplo, Chrome, Safari, Firefox) + RegisterTokenButtonText: Adicionar chave de segurança + ErrorRetry: Tentar novamente, criar um novo desafio ou escolher um método diferente. + +InitMFADone: + Title: Chave de segurança verificada + Description: Incrível! Você configurou com sucesso a autenticação de 2 fatores e tornou sua conta muito mais segura. O fator deve ser inserido em cada login. + NextButtonText: próximo + CancelButtonText: cancelar + +MFAProvider: + Provider0: Aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy) + Provider1: Dependente do dispositivo (por exemplo, FaceID, Windows Hello, Impressão digital) + ChooseOther: ou escolha outra opção + +VerifyMFAOTP: + Title: Verificar 2 fatores + Description: Verifique seu segundo fator + CodeLabel: Código + NextButtonText: próximo + +VerifyMFAU2F: + Title: Verificação de 2 fatores + Description: Verifique seu 2 fatores com o dispositivo registrado (por exemplo, FaceID, Windows Hello, Impressão digital) + NotSupported: WebAuthN não é suportado pelo seu navegador. Verifique se está usando a versão mais recente ou altere para um navegador compatível (Chrome, Safari, Firefox) + ErrorRetry: Tentar novamente, criar uma nova solicitação ou escolher outro método. + ValidateTokenButtonText: Verificar 2 fatores + +Passwordless: + Title: Login sem senha + Description: Faça login com métodos de autenticação fornecidos pelo seu dispositivo, como FaceID, Windows Hello ou Impressão digital. + NotSupported: WebAuthN não é suportado pelo seu navegador. Verifique se ele está atualizado ou use outro navegador (por exemplo, Chrome, Safari, Firefox) + ErrorRetry: Tentar novamente, criar um novo desafio ou escolher um método diferente. + LoginWithPwButtonText: Fazer login com senha + ValidateTokenButtonText: Fazer login sem senha + +PasswordlessPrompt: + Title: Configuração de login sem senha + Description: Você gostaria de configurar o login sem senha? (Métodos de autenticação do seu dispositivo, como FaceID, Windows Hello ou Impressão digital) + +PasswordlessRegistration: + Title: Configuração de login sem senha + Description: Adicione sua autenticação fornecendo um nome (por exemplo, MeuCelular, MacBook, etc.) e clique no botão 'Registrar login sem senha' abaixo. + TokenNameLabel: Nome do dispositivo + NotSupported: WebAuthN não é suportado pelo seu navegador. Verifique se ele está atualizado ou use outro navegador (por exemplo, Chrome, Safari, Firefox) + RegisterTokenButtonText: Registrar login sem senha + ErrorRetry: Tentar novamente, criar um novo desafio ou escolher um método diferente. + +PasswordlessRegistrationDone: + Title: Configuração de login sem senha concluída + Description: Dispositivo para login sem senha adicionado com sucesso. + DescriptionClose: Agora você pode fechar esta janela. + NextButtonText: próximo + CancelButtonText: cancelar + +PasswordChange: + Title: Alterar senha + Description: Altere sua senha. Insira sua senha antiga e nova. + OldPasswordLabel: Senha antiga + NewPasswordLabel: Nova senha + NewPasswordConfirmLabel: Confirmação de senha + CancelButtonText: cancelar + NextButtonText: próximo + Footer: Rodapé + +PasswordChangeDone: + Title: Alteração de senha + Description: Sua senha foi alterada com sucesso. + NextButtonText: próximo + +PasswordResetDone: + Title: Link de redefinição de senha enviado + Description: Verifique seu e-mail para redefinir sua senha. + NextButtonText: próximo + +EmailVerification: + Title: Verificação de e-mail + Description: Enviamos um e-mail para verificar seu endereço. Insira o código no formulário abaixo. + CodeLabel: Código + NextButtonText: próximo + ResendButtonText: reenviar código + +EmailVerificationDone: + Title: Verificação de e-mail + Description: Seu endereço de e-mail foi verificado com sucesso. + NextButtonText: próximo + CancelButtonText: cancelar + LoginButtonText: login + +RegisterOption: + Title: Opções de registro + Description: Escolha como deseja se registrar + RegisterUsernamePasswordButtonText: Com nome de usuário e senha + ExternalLoginDescription: ou registre-se com um usuário externo + LoginButtonText: login + +RegistrationUser: + Title: Registro + Description: Insira seus dados de usuário. Seu endereço de e-mail será usado como nome de login. + DescriptionOrgRegister: Insira seus dados de usuário. + EmailLabel: E-mail + UsernameLabel: Nome de usuário + FirstnameLabel: Nome próprio + LastnameLabel: Sobrenome + LanguageLabel: Idioma + German: Alemão + English: Inglês + Italian: Italiano + French: Francês + Chinese: Chinês simplificado + Polish: Polonês + Japanese: Japonês + Spanish: Espanhol + Bulgarian: Búlgaro + Portuguese: Português + Macedonian: Македонски + GenderLabel: Gênero + Female: Feminino + Male: Masculino + Diverse: Diverso / X + PasswordLabel: Senha + PasswordConfirmLabel: Confirmação de senha + TosAndPrivacyLabel: Termos e condições + TosConfirm: Eu aceito os + TosLinkText: termos de serviço + PrivacyConfirm: Eu aceito a + PrivacyLinkText: política de privacidade + ExternalLogin: ou registre-se com um usuário externo + BackButtonText: login + NextButtonText: próximo + +ExternalRegistrationUserOverview: + Title: Registro de usuário externo + Description: Coletamos seus detalhes de usuário do provedor selecionado. Agora você pode alterá-los ou completá-los. + EmailLabel: E-mail + UsernameLabel: Nome de usuário + FirstnameLabel: Nome próprio + LastnameLabel: Sobrenome + NicknameLabel: Apelido + PhoneLabel: Número de telefone + LanguageLabel: Idioma + German: Alemão + English: Inglês + Italian: Italiano + French: Francês + Chinese: Chinês simplificado + Japanese: Japonês + Polish: Polonês + Spanish: Espanhol + Portuguese: Português + Macedonian: Македонски + TosAndPrivacyLabel: Termos e condições + TosConfirm: Eu aceito os + TosLinkText: termos de serviço + PrivacyConfirm: Eu aceito a + PrivacyLinkText: política de privacidade + ExternalLogin: ou registre-se com um usuário externo + BackButtonText: voltar + NextButtonText: salvar + +RegistrationOrg: + Title: Registro de organização + Description: Insira o nome de sua organização e seus dados de usuário. + OrgNameLabel: Nome da organização + EmailLabel: E-mail + UsernameLabel: Nome de usuário + FirstnameLabel: Nome próprio + LastnameLabel: Sobrenome + PasswordLabel: Senha + PasswordConfirmLabel: Confirmação de senha + TosAndPrivacyLabel: Termos e condições + TosConfirm: Eu aceito os + TosLinkText: termos de serviço + PrivacyConfirm: Eu aceito a + PrivacyLinkText: política de privacidade + SaveButtonText: Criar organização + +LoginSuccess: + Title: Login bem-sucedido + AutoRedirectDescription: Você será redirecionado de volta para o seu aplicativo automaticamente. Se isso não acontecer, clique no botão abaixo. Você pode fechar a janela em seguida. + RedirectedDescription: Agora você pode fechar esta janela. + NextButtonText: próximo + +LogoutDone: + Title: Logout concluído + Description: Você fez logout com sucesso. + LoginButtonText: login + +LinkingUsersDone: + Title: Vinculação de usuários + Description: Vinculação de usuários concluída. + CancelButtonText: cancelar + NextButtonText: próximo + +ExternalNotFound: + Title: Usuário externo não encontrado + Description: Usuário externo não encontrado. Deseja vincular seu usuário ou registrar um novo. + LinkButtonText: Vincular + AutoRegisterButtonText: registrar + TosAndPrivacyLabel: Termos e condições + TosConfirm: Eu aceito os + TosLinkText: termos de serviço + PrivacyConfirm: Eu aceito a + PrivacyLinkText: política de privacidade + German: Alemão + English: Inglês + Italian: Italiano + French: Francês + Chinese: Chinês simplificado + Polish: Polonês + Japanese: Japonês + Spanish: Espanhol + Bulgarian: Búlgaro + Portuguese: Português + Macedonian: Македонски +DeviceAuth: + Title: Autorização de dispositivo + UserCode: + Label: Código do usuário + Description: Insira o código do usuário apresentado no dispositivo. + ButtonNext: próximo + Action: + Description: Conceder acesso ao dispositivo. + GrantDevice: você está prestes a conceder acesso aodispositivo + AccessToScopes: acesso às seguintes permissões + Button: + Allow: permitir + Deny: negar + Done: + Description: Concluído. + Approved: Autorização de dispositivo aprovada. Agora você pode voltar ao dispositivo. + Denied: Autorização de dispositivo negada. Agora você pode voltar ao dispositivo. + +Footer: + PoweredBy: Desenvolvido por + Tos: Termos de serviço + PrivacyPolicy: Política de privacidade + Help: Ajuda + SupportEmail: E-mail de suporte + +Errors: + Internal: Ocorreu um erro interno + AuthRequest: + NotFound: Não foi possível encontrar a solicitação de autenticação + UserAgentNotCorresponding: O agente do usuário não corresponde + UserAgentNotFound: ID do agente do usuário não encontrado + TokenNotFound: Token não encontrado + RequestTypeNotSupported: Tipo de solicitação não suportado + MissingParameters: Parâmetros obrigatórios faltando + User: + NotFound: O usuário não pôde ser encontrado + AlreadyExists: O usuário já existe + Inactive: O usuário está inativo + NotFoundOnOrg: O usuário não pôde ser encontrado na organização escolhida + NotAllowedOrg: O usuário não é membro da organização requerida + NotMatchingUserID: O usuário e o usuário na solicitação de autenticação não correspondem + UserIDMissing: O ID do usuário está vazio + Invalid: Dados de usuário inválidos + DomainNotAllowedAsUsername: O domínio já está reservado e não pode ser usado + NotAllowedToLink: O usuário não está autorizado a vincular com provedor de login externo + Profile: + NotFound: Perfil não encontrado + NotChanged: Perfil não foi alterado + Empty: O perfil está vazio + FirstNameEmpty: O nome próprio no perfil está vazio + LastNameEmpty: O sobrenome no perfil está vazio + IDMissing: ID do perfil está faltando + Email: + NotFound: E-mail não encontrado + Invalid: E-mail inválido + AlreadyVerified: O e-mail já está verificado + NotChanged: E-mail não foi alterado + Empty: O e-mail está vazio + IDMissing: ID do e-mail está faltando + Phone: + NotFound: Número de telefone não encontrado + Invalid: Número de telefone inválido + AlreadyVerified: O número de telefone já está verificado + Empty: O número de telefone está vazio + NotChanged: O número de telefone não foi alterado + Address: + NotFound: Endereço não encontrado + NotChanged: Endereço não foi alterado + Username: + AlreadyExists: Nome de usuário já está em uso + Reserved: O nome de usuário já está em uso + Empty: O nome de usuário está vazio + Password: + ConfirmationWrong: A confirmação da senha está incorreta + Empty: A senha está vazia + Invalid: A senha é inválida + InvalidAndLocked: A senha é inválida e o usuário está bloqueado, entre em contato com o administrador. + UsernameOrPassword: + Invalid: Nome de usuário ou senha inválidos + PasswordComplexityPolicy: + NotFound: Política de complexidade de senha não encontrada + MinLength: A senha é muito curta + HasLower: A senha deve conter letra minúscula + HasUpper: A senha deve conter letra maiúscula + HasNumber: A senha deve conter número + HasSymbol: A senha deve conter símbolo + Code: + Expired: O código expirou + Invalid: O código é inválido + Empty: O código está vazio + CryptoCodeNil: O código criptografado está nulo + NotFound: Não foi possível encontrar o código + GeneratorAlgNotSupported: Algoritmo do gerador não suportado + EmailVerify: + UserIDEmpty: O ID do usuário está vazio + ExternalData: + CouldNotRead: Não foi possível ler os dados externos corretamente + MFA: + NoProviders: Nenhum provedor de autenticação de vários fatores disponível + OTP: + AlreadyReady: A autenticação de vários fatores por OTP (senha única) já está configurada + NotExisting: A autenticação de vários fatores por OTP (senha única) não existe + InvalidCode: Código inválido + NotReady: A autenticação de vários fatores por OTP (senha única) não está pronta + Locked: O usuário está bloqueado + SomethingWentWrong: Algo deu errado + NotActive: O usuário não está ativo + ExternalIDP: + IDPTypeNotImplemented: Tipo de provedor de login externo não implementado + NotAllowed: Provedor de login externo não permitido + IDPConfigIDEmpty: ID do Provedor de Identidade está vazio + ExternalUserIDEmpty: ID do usuário externo está vazio + UserDisplayNameEmpty: O nome de exibição do usuário está vazio + NoExternalUserData: Nenhum dado de usuário externo recebido + CreationNotAllowed: A criação de um novo usuário não é permitida neste provedor + LinkingNotAllowed: A vinculação de um usuário não é permitida neste provedor + GrantRequired: Login não é possível. O usuário precisa ter pelo menos uma permissão no aplicativo. Entre em contato com o administrador. + ProjectRequired: Login não é possível. A organização do usuário precisa ser concedida ao projeto. Entre em contato com o administrador. + IdentityProvider: + InvalidConfig: Configuração do provedor de identidade inválida + IAM: + LockoutPolicy: + NotExisting: Política de bloqueio não existe + Org: + LoginPolicy: + RegistrationNotAllowed: O registro não é permitido + DeviceAuth: + NotExisting: Código do usuário não existe + +optional: (opcional) diff --git a/internal/api/ui/login/static/i18n/zh.yaml b/internal/api/ui/login/static/i18n/zh.yaml index f44b39bc6..0680fa267 100644 --- a/internal/api/ui/login/static/i18n/zh.yaml +++ b/internal/api/ui/login/static/i18n/zh.yaml @@ -223,6 +223,8 @@ RegistrationUser: Japanese: 日本語 Spanish: Español Bulgarian: Български + Portuguese: Português + Macedonian: Македонски GenderLabel: 性别 Female: 女性 Male: 男性 @@ -256,6 +258,7 @@ ExternalRegistrationUserOverview: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски TosAndPrivacyLabel: 条款和条款 TosConfirm: 我接受 TosLinkText: 服务条款 @@ -317,6 +320,7 @@ ExternalNotFound: Polish: Polski Japanese: 日本語 Spanish: Español + Macedonian: Македонски DeviceAuth: Title: 设备授权 diff --git a/internal/api/ui/login/static/resources/images/idp/ms.svg b/internal/api/ui/login/static/resources/images/idp/ms.svg new file mode 100644 index 000000000..1f7397648 --- /dev/null +++ b/internal/api/ui/login/static/resources/images/idp/ms.svg @@ -0,0 +1 @@ +MS-SymbolLockup \ No newline at end of file diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_base.scss b/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_base.scss index 074ebd346..a558e1435 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_base.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_base.scss @@ -1,68 +1,78 @@ -$lgn-idp-margin: .5rem 0; +$lgn-idp-margin: 0.5rem 0; $lgn-idp-padding: 0 1px; $lgn-idp-provider-name-line-height: 36px; -$lgn-idp-border-radius: .5rem; -$googlelogosource: '../../../images/idp/google'; -$githublogosource: '../../../images/idp/github'; -$gitlablogosource: '../../../images/idp/gitlab'; +$lgn-idp-border-radius: 0.5rem; @mixin lgn-idp-base { - display: block; - margin: $lgn-idp-margin; - box-sizing: border-box; - display: flex; - align-items: center; - position: relative; - padding: $lgn-idp-padding; - border-radius: $lgn-idp-border-radius; - border-width: 1px; - border-style: solid; - + display: block; + margin: $lgn-idp-margin; + box-sizing: border-box; + display: flex; + align-items: center; + position: relative; + padding: $lgn-idp-padding; + border-radius: $lgn-idp-border-radius; + border-width: 1px; + border-style: solid; + transition: border-color 0.2s ease-in-out; + + span.logo { + height: 46px; + width: 46px; + } + + span.provider-name { + line-height: $lgn-idp-provider-name-line-height; + position: absolute; + left: 50%; + transform: translateX(-50%); + } + + &.google { span.logo { - height: 46px; - width: 46px; + height: 46px; + width: 46px; + background-image: var(--google-image-src); + background-size: 25px; + background-position: center; + background-repeat: no-repeat; + border-radius: 5px; } + } - span.provider-name { - line-height: $lgn-idp-provider-name-line-height; - position: absolute; - left: 50%; - transform: translateX(-50%); - } - - &.google { - span.logo { - height: 46px; - width: 46px; - background-image: url($googlelogosource + '.png'); - background-size: 25px; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; - } + &.github { + span.logo { + height: 46px; + width: 46px; + background-image: var(--github-image-src); + background-size: 25px; + background-position: center; + background-repeat: no-repeat; + border-radius: 5px; } + } - &.github { - span.logo { - height: 46px; - width: 46px; - background-image: url($githublogosource + '.png'); - background-size: 25px; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; - } + &.gitlab { + span.logo { + height: 46px; + width: 46px; + background-image: var(--gitlab-image-src); + background-size: 100%; + background-position: center; + background-repeat: no-repeat; + border-radius: 5px; } + } - &.gitlab { - span.logo { - height: 46px; - width: 46px; - background-image: url($gitlablogosource + '.png'); - background-size: 100%; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; - } + &.azure { + span.logo { + height: 46px; + width: 46px; + background-image: var(--azure-image-src); + background-size: 25px; + background-position: center; + background-repeat: no-repeat; + border-radius: 5px; } + } } diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_theme.scss b/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_theme.scss index 0d29a038c..f05846faf 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_theme.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/identity_provider/identity_provider_theme.scss @@ -10,26 +10,11 @@ color: var(--zitadel-color-text-500); &:hover { - @include lgn-idp-elevation(1); + border-color: var(--zitadel-color-input-border-hover); } &:not([disabled]):active { - @include lgn-idp-elevation(2); - } - - &.google { - color: var(--zitadel-color-google-text); - background-color: var(--zitadel-color-google-background); - } - - &.github { - color: var(--zitadel-color-github-text); - background-color: var(--zitadel-color-github-background); - } - - &.gitlab { - color: var(--zitadel-color-gitlab-text); - background-color: var(--zitadel-color-gitlab-background); + border-color: var(--zitadel-color-input-border-active); } } diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/vars.scss b/internal/api/ui/login/static/resources/themes/scss/styles/vars.scss index 304ed8a4f..3242e5f45 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/vars.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/vars.scss @@ -108,8 +108,8 @@ --zitadel-color-grey-800: #424242; --zitadel-color-grey-900: #212121; - --zitadel-icon-select: url("../select_arrow_light.svg"); - --zitadel-logo-powered-by: url("../logo-dark.svg"); + --zitadel-icon-select: url(../../zitadel/select_arrow_light.svg); + --zitadel-logo-powered-by: url(../../zitadel/logo-dark.svg); --zitadel-color-google-text: #8b8d8d; --zitadel-color-google-background: #ffffff; @@ -120,6 +120,11 @@ --zitadel-color-qr: var(--zitadel-color-black); --zitadel-color-qr-background: var(--zitadel-color-white); + + --google-image-src: url(../../../images/idp/google.png); + --github-image-src: url(../../../images/idp/github.png); + --gitlab-image-src: url(../../../images/idp/gitlab.png); + --azure-image-src: url(../../../images/idp/ms.svg); } .lgn-dark-theme { @@ -213,8 +218,8 @@ ); /*--zitadel-color-label: var(--zitadel-color-grey-600); same */ - --zitadel-icon-select: url("../select_arrow_dark.svg"); - --zitadel-logo-powered-by: url("../logo-light.svg"); + --zitadel-icon-select: url(../../zitadel/select_arrow_dark.svg); + --zitadel-logo-powered-by: url(../../zitadel/logo-light.svg); --zitadel-color-google-text: #8b8d8d; --zitadel-color-google-background: #ffffff; @@ -222,4 +227,9 @@ --zitadel-color-github-background: #ffffff; --zitadel-color-gitlab-text: #8b8d8d; --zitadel-color-gitlab-background: #ffffff; + + --google-image-src: url(../../../images/idp/google.png); + --github-image-src: url(../../../images/idp/github-white.png); + --gitlab-image-src: url(../../../images/idp/gitlab.png); + --azure-image-src: url(../../../images/idp/ms.svg); } diff --git a/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css b/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css deleted file mode 100644 index 6f7a3e972..000000000 --- a/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css +++ /dev/null @@ -1,3125 +0,0 @@ -@charset "UTF-8"; -:root { - --zitadel-color-primary: var(--zitadel-color-primary-500); - --zitadel-color-background: var(--zitadel-color-background-500); - --zitadel-color-warn: var(--zitadel-color-warn-500); - --zitadel-color-text: var(--zitadel-color-text-500); - --zitadel-color-primary-50: #eaedfa; - --zitadel-color-primary-100: #ccd2f2; - --zitadel-color-primary-200: #aab4ea; - --zitadel-color-primary-300: #8796e1; - --zitadel-color-primary-400: #6e80da; - --zitadel-color-primary-500: #5469d4; - --zitadel-color-primary-600: #4d61cf; - --zitadel-color-primary-700: #4356c9; - --zitadel-color-primary-800: #3a4cc3; - --zitadel-color-primary-900: #293bb9; - --zitadel-color-primary-rgb: rgb(84, 105, 212); - --zitadel-color-primary-contrast: var(--zitadel-color-white); - --zitadel-color-warn-50: #f9e7eb; - --zitadel-color-warn-100: #f0c4cc; - --zitadel-color-warn-200: #e69dab; - --zitadel-color-warn-300: #dc7689; - --zitadel-color-warn-400: #d5586f; - --zitadel-color-warn-500: #cd3b56; - --zitadel-color-warn-600: #c8354f; - --zitadel-color-warn-700: #c12d45; - --zitadel-color-warn-800: #ba263c; - --zitadel-color-warn-900: #ae192b; - --zitadel-font-family: "Lato"; - --zitadel-color-background-50: rgb(255, 255, 255); - --zitadel-color-background-100: rgb(255, 255, 255); - --zitadel-color-background-200: rgb(255, 255, 255); - --zitadel-color-background-300: rgb(255, 255, 255); - --zitadel-color-background-400: rgb(255, 255, 255); - --zitadel-color-background-500: rgb(250, 250, 250); - --zitadel-color-background-600: rgb(222, 222, 222); - --zitadel-color-background-700: rgb(195, 195, 194); - --zitadel-color-background-800: rgb(168, 168, 168); - --zitadel-color-background-900: rgb(142, 142, 142); - --zitadel-color-background-contrast: rgb(0, 0, 0); - --zitadel-color-footer-line: rgba(0, 0, 0, 0.12); - --zitadel-color-card-hover: #ffffff; - --zitadel-color-input-background: #00000003; - --zitadel-color-input-border: #1a191938; - --zitadel-color-input-border-hover: #1a1b1b; - --zitadel-color-input-border-active: var(--zitadel-color-primary-500); - --zitadel-color-input-placeholder: var(--zitadel-color-grey-600); - --zitadel-color-text-50: rgb(0, 0, 0); - --zitadel-color-text-100: rgb(0, 0, 0); - --zitadel-color-text-200: rgb(0, 0, 0); - --zitadel-color-text-300: rgb(0, 0, 0); - --zitadel-color-text-400: rgb(0, 0, 0); - --zitadel-color-text-500: rgb(0, 0, 0); - --zitadel-color-text-600: rgb(0, 0, 0); - --zitadel-color-text-700: rgb(0, 0, 0); - --zitadel-color-text-800: rgb(0, 0, 0); - --zitadel-color-text-900: rgb(0, 0, 0); - --zitadel-color-text-contrast: rgb(255, 255, 255); - --zitadel-color-label: #0000008a; - --zitadel-color-account-selector-hover: rgba(0, 0, 0, 0.02); - --zitadel-color-account-selector-active: rgba(0, 0, 0, 0.05); - --zitadel-color-success: #0e6245; - --zitadel-color-success-background: #cbf4c9; - --zitadel-color-state-success-font: #0e6245; - --zitadel-color-state-success-background: #cbf4c9; - --zitadel-color-state-warn-font: #620e0e; - --zitadel-color-state-warn-background: #ffc1c1; - --zitadel-color-footer-background: #00000002; - --zitadel-color-footer-background-mozilla: var( - --zitadel-color-background-600 - ); - --zitadel-color-divider: rgba(0, 0, 0, 0.12); - --zitadel-color-button-disabled: rgba(0, 0, 0, 0.26); - --zitadel-color-button-disabled-background: rgba(0, 0, 0, 0.12); - --zitadel-color-button-selected-background: var(--zitadel-color-grey-900); - --zitadel-color-button-disabled-selected-background: var( - --zitadel-color-grey-800 - ); - --zitadel-color-raised-button-background: var(--zitadel-color-white); - --zitadel-color-stroked-button-hover-background: #00000010; - --zitadel-color-stroked-button-active-background: #00000020; - --zitadel-color-raised-button-active-background: var( - --zitadel-color-primary-700 - ); - --zitadel-color-white: #ffffff; - --zitadel-color-black: #000000; - --zitadel-color-grey-50: #fafafa; - --zitadel-color-grey-100: #f5f5f5; - --zitadel-color-grey-200: #eeeeee; - --zitadel-color-grey-300: #e0e0e0; - --zitadel-color-grey-400: #bdbdbd; - --zitadel-color-grey-500: #9e9e9e; - --zitadel-color-grey-600: #757575; - --zitadel-color-grey-700: #616161; - --zitadel-color-grey-800: #424242; - --zitadel-color-grey-900: #212121; - --zitadel-icon-select: url("../select_arrow_light.svg"); - --zitadel-logo-powered-by: url("../logo-dark.svg"); - --zitadel-color-google-text: #8b8d8d; - --zitadel-color-google-background: #ffffff; - --zitadel-color-github-text: #8b8d8d; - --zitadel-color-github-background: #ffffff; - --zitadel-color-gitlab-text: #8b8d8d; - --zitadel-color-gitlab-background: #ffffff; - --zitadel-color-qr: var(--zitadel-color-black); - --zitadel-color-qr-background: var(--zitadel-color-white); -} - -.lgn-dark-theme { - --zitadel-color-primary-50: #f1f7fd; - --zitadel-color-primary-100: #afd1f2; - --zitadel-color-primary-200: #7fb5ea; - --zitadel-color-primary-300: #4192e0; - --zitadel-color-primary-400: #2782dc; - --zitadel-color-primary-500: #2073c4; - --zitadel-color-primary-600: #1c64aa; - --zitadel-color-primary-700: #17548f; - --zitadel-color-primary-800: #134575; - --zitadel-color-primary-900: #0f355b; - --zitadel-color-warn-50: #ffe7eb; - --zitadel-color-warn-100: #ffc4ce; - --zitadel-color-warn-200: #ff9dad; - --zitadel-color-warn-300: #ff768c; - --zitadel-color-warn-400: #ff5874; - --zitadel-color-warn-500: #ff3b5b; - --zitadel-color-warn-600: #ff3553; - --zitadel-color-warn-700: #ff2d49; - --zitadel-color-warn-800: #ff2640; - --zitadel-color-warn-900: #ff192f; - --zitadel-font-family: "Lato"; - --zitadel-color-background-50: rgb(60, 60, 60); - --zitadel-color-background-100: rgb(55, 55, 55); - --zitadel-color-background-200: rgb(49, 49, 49); - --zitadel-color-background-300: rgb(44, 44, 44); - --zitadel-color-background-400: rgb(36, 36, 36); - --zitadel-color-background-500: rgb(33, 33, 33); - --zitadel-color-background-600: rgb(30, 30, 30); - --zitadel-color-background-700: rgb(28, 28, 28); - --zitadel-color-background-800: rgb(25, 25, 25); - --zitadel-color-background-900: rgb(23, 23, 23); - --zitadel-color-background-contrast: rgb(255, 255, 255); - --zitadel-color-footer-line: rgba(255, 255, 255, 0.12); - --zitadel-color-card-hover: #ffffff20; - --zitadel-color-input-background: rgba(0, 0, 0, 0.2); - --zitadel-color-input-border: #f9f7f725; - --zitadel-color-input-border-hover: #ffffff; - --zitadel-color-input-border-active: var(--zitadel-color-primary-500); - --zitadel-color-input-placeholder: var(--zitadel-color-grey-600); - --zitadel-color-text-50: rgb(255, 255, 255); - --zitadel-color-text-100: rgb(255, 255, 255); - --zitadel-color-text-200: rgb(255, 255, 255); - --zitadel-color-text-300: rgb(255, 255, 255); - --zitadel-color-text-400: rgb(255, 255, 255); - --zitadel-color-text-500: rgb(255, 255, 255); - --zitadel-color-text-600: rgb(221, 222, 223); - --zitadel-color-text-700: rgb(194, 195, 195); - --zitadel-color-text-800: rgb(167, 168, 169); - --zitadel-color-text-900: rgb(141, 142, 143); - --zitadel-color-text-contrast: rgb(0, 0, 0); - --zitadel-color-label: #ffffffb3; - --zitadel-color-account-selector-hover: rgba(255, 255, 255, 0.02); - --zitadel-color-account-selector-active: rgba(255, 255, 255, 0.05); - --zitadel-color-success: #cbf4c9; - --zitadel-color-success-background: #4f566b; - --zitadel-color-state-success-font: #cbf4c9; - --zitadel-color-state-success-background: #68cf8340; - --zitadel-color-state-warn-font: #ffc1c1; - --zitadel-color-state-warn-background: #af455359; - --zitadel-color-footer-background: #00000020; - --zitadel-color-footer-background-mozilla: var( - --zitadel-color-background-600 - ); - --zitadel-color-divider: rgba(255, 255, 255, 0.12); - --zitadel-color-button-disabled: rgba(0, 0, 0, 0.26); - --zitadel-color-button-disabled-background: rgba(255, 255, 255, 0.12); - --zitadel-color-button-selected-background: var(--zitadel-color-grey-900); - --zitadel-color-button-disabled-selected-background: var( - --zitadel-color-grey-800 - ); - --zitadel-color-raised-button-background: var(--zitadel-color-grey-800); - --zitadel-color-stroked-button-hover-background: #ffffff10; - --zitadel-color-stroked-button-active-background: #ffffff20; - --zitadel-color-raised-button-active-background: var( - --zitadel-color-primary-300 - ); - /*--zitadel-color-label: var(--zitadel-color-grey-600); same */ - --zitadel-icon-select: url("../select_arrow_dark.svg"); - --zitadel-logo-powered-by: url("../logo-light.svg"); - --zitadel-color-google-text: #8b8d8d; - --zitadel-color-google-background: #ffffff; - --zitadel-color-github-text: #8b8d8d; - --zitadel-color-github-background: #ffffff; - --zitadel-color-gitlab-text: #8b8d8d; - --zitadel-color-gitlab-background: #ffffff; -} - -body { - margin: 0 auto; - display: flex; - flex-direction: column; - height: 100vh; -} -body .lgn-grow { - flex: 1; -} -body.waiting * { - cursor: wait !important; -} - -.hidden { - display: none !important; -} - -.text-align-center { - text-align: center; -} - -footer { - width: 100%; - box-sizing: border-box; - background: #00000020; - min-height: 50px; - display: flex; - align-items: center; - padding: 0 1rem; -} -footer .fill-space { - flex: 1; -} -footer a { - font-size: 12px; - margin-left: 1rem; - display: block; -} -@media only screen and (min-width: 600px) { - footer { - position: fixed; - bottom: 0; - left: 0; - right: 0; - } -} -footer .watermark { - display: flex; -} -footer .watermark .powered { - font-size: 12px; - margin: auto 2px; - display: none; -} -@media only screen and (min-width: 600px) { - footer .watermark .powered { - display: inline-block; - } -} -footer .watermark .lgn-logo-watermark { - height: 40px; - min-width: 125px; - margin: auto 2px; -} - -.lgn-header { - display: flex; - position: relative; - margin: auto; - padding: 0; - max-width: 250px; - min-height: 150px; - align-items: center; - justify-content: center; -} -.lgn-header .lgn-logo { - display: block; - height: 100%; - margin: 0 auto; - max-width: 250px; - max-height: 150px; - object-fit: contain; -} - -.lgn-button, .lgn-stroked-button, .lgn-icon-button { - box-sizing: border-box; - position: relative; - cursor: pointer; - outline: none; - border: none; - -webkit-tap-highlight-color: transparent; - display: inline-block; - white-space: nowrap; - text-decoration: none; - vertical-align: baseline; - text-align: center; - margin: 0; - min-width: 64px; - line-height: 36px; - padding: 0 16px; - border-radius: 6px; - overflow: visible; - transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); -} -.lgn-button[disabled], .lgn-stroked-button[disabled], .lgn-icon-button[disabled] { - cursor: default; -} -.lgn-button::-moz-focus-inner, .lgn-stroked-button::-moz-focus-inner, .lgn-icon-button::-moz-focus-inner { - border: 0; -} - -.lgn-raised-button { - box-sizing: border-box; - position: relative; - cursor: pointer; - outline: none; - border: none; - -webkit-tap-highlight-color: transparent; - display: inline-block; - white-space: nowrap; - text-decoration: none; - vertical-align: baseline; - text-align: center; - margin: 0; - min-width: 64px; - line-height: 36px; - padding: 0 16px; - border-radius: 6px; - overflow: visible; - transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); - transform: translate3d(0, 0, 0); -} -.lgn-raised-button[disabled] { - cursor: default; -} -.lgn-raised-button::-moz-focus-inner { - border: 0; -} - -.lgn-icon-button { - padding: 0; - min-width: 0; - width: 40px; - height: 40px; - flex-shrink: 0; - line-height: 40px; - border-radius: 50%; -} -.lgn-icon-button i, .lgn-icon-button .mat-icon { - line-height: 40px; -} - -.lgn-stroked-button { - border: 1px solid currentColor; - padding: 0 15px; - line-height: 34px; -} - -.lgn-button:focus { - pointer-events: none; - transition: opacity 200ms cubic-bezier(0.35, 0, 0.25, 1), background-color 200ms cubic-bezier(0.35, 0, 0.25, 1); -} - -.lgn-button *, .lgn-stroked-button *, .lgn-raised-button * { - vertical-align: middle; -} - -input:not([type=radio]):not([type=checkbox]), -.lgn-input { - display: block; - box-sizing: border-box; - padding-inline-start: 10px; - outline: none; - display: inline-block; - text-align: start; - cursor: text; - border-radius: 4px; - transform: all 0.2 linear; - font-size: 1rem; - border-style: solid; - border-width: 1px; - height: 40px; - padding: 10px; - transition: border-color 0.2s ease-in-out; - width: 100%; - margin: 0 0 2px 0; -} -input:not([type=radio]):not([type=checkbox])::placeholder, -.lgn-input::placeholder { - font-size: 14px; - font-style: italic; -} - -select, -.lgn-select { - display: block; - box-sizing: border-box; - padding-inline-start: 10px; - outline: none; - display: inline-block; - text-align: start; - cursor: text; - border-radius: 4px; - transform: all 0.2 linear; - font-size: 1rem; - border-style: solid; - border-width: 1px; - height: 40px; - padding: 10px; - transition: border-color 0.2s ease-in-out; - width: 100%; - margin: 0 0 2px 0; -} -select::placeholder, -.lgn-select::placeholder { - font-size: 14px; - font-style: italic; -} - -.lgn-suffix-wrapper { - position: relative; -} -.lgn-suffix-wrapper [lgnSuffix] { - position: absolute; - right: 0.5rem; - top: 9px; - height: inherit; - vertical-align: middle; - max-width: 150px; - overflow-x: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.lgn-label { - display: block; - font-size: 12px; - transition: color 0.2s ease; - margin: 0 0 2px 0; - font-weight: 400; -} -.lgn-label * { - font-size: 12px; -} - -@keyframes ripple { - 0% { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0); - } - 50% { - box-shadow: 0 0 0 15px rgba(0, 0, 0, 0.1); - } - 100% { - box-shadow: 0 0 0 15px rgba(0, 0, 0, 0); - } -} -.lgn-radio { - outline: none; - margin: 16px 0; - display: inline-block; -} -.lgn-radio.block { - display: block; -} -.lgn-radio label { - display: inline-block; - height: 20px; - position: relative; - padding: 0 0 0 30px; - margin-bottom: 0; - cursor: pointer; - vertical-align: middle; - padding-top: 2px; - outline: none; - font-size: 14px; - line-height: 16px; -} -.lgn-radio label::before, .lgn-radio label::after { - position: absolute; - content: ""; - border-radius: 50%; - transition: all 0.3s ease; - transition-property: transform, border-color; -} -.lgn-radio label::before { - left: 0; - top: 0; - width: 20px; - height: 20px; - border-width: 2px; - border-style: solid; -} -.lgn-radio label::after { - top: 5px; - left: 5px; - width: 10px; - height: 10px; - transform: scale(0); -} -.lgn-radio input[type=radio] { - display: block; - opacity: 0; - margin: 0; - width: 0; - height: 0; - outline: none; -} -.lgn-radio input[type=radio]:checked + label::before { - animation: ripple 0.2s linear forwards; -} -.lgn-radio input[type=radio]:checked + label::after { - transform: scale(1); -} -.lgn-radio input[type=radio]:focus + label { - opacity: 1; -} -.lgn-radio input[type=radio]:disabled + label { - cursor: not-allowed; - font-style: italic; -} -.lgn-radio input[type=radio]:disabled:focus { - opacity: 0; -} -.lgn-radio *, -.lgn-radio *::before, -.lgn-radio *::after { - box-sizing: border-box; -} - -a { - text-decoration: none; - cursor: pointer; - margin: 2px 0; -} -a.block { - display: block; -} -a.sub-formfield-link { - margin: 10px 0; - text-decoration: underline; -} - -.lgn-idp { - display: block; - margin: 0.5rem 0; - box-sizing: border-box; - display: flex; - align-items: center; - position: relative; - padding: 0 1px; - border-radius: 0.5rem; - border-width: 1px; - border-style: solid; -} -.lgn-idp span.logo { - height: 46px; - width: 46px; -} -.lgn-idp span.provider-name { - line-height: 36px; - position: absolute; - left: 50%; - transform: translateX(-50%); -} -.lgn-idp.google span.logo { - height: 46px; - width: 46px; - background-image: url("../../../images/idp/google.png"); - background-size: 25px; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; -} -.lgn-idp.github span.logo { - height: 46px; - width: 46px; - background-image: url("../../../images/idp/github.png"); - background-size: 25px; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; -} -.lgn-idp.gitlab span.logo { - height: 46px; - width: 46px; - background-image: url("../../../images/idp/gitlab.png"); - background-size: 100%; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; -} - -.lgn-error { - display: flex; - align-items: center; - outline: none; -} -.lgn-error i { - margin-right: 0.5rem; - font-size: 1.5rem; -} - -#wa-error { - flex-direction: column; -} - -.lgn-qrcode { - display: block; - margin: auto; - margin: 1rem 0; - margin-bottom: 1.5rem; -} -.lgn-qrcode svg { - margin: auto; - display: block; - border-radius: 0.5rem; -} - -.lgn-max-width-wrapper { - max-width: 440px; - margin: auto; - margin-top: 50px; - margin-bottom: 50px; - display: block; -} -@media only screen and (min-width: 600px) { - .lgn-max-width-wrapper { - margin-top: 100px; - } -} - -.content-container { - position: relative; - display: block; - margin: 0 auto 0 auto; - padding: 20px; - width: 100%; - box-sizing: border-box; -} -.content-container .lgn-head h1 { - text-align: center; -} -.content-container .lgn-head p { - text-align: center; -} -.content-container .lgn-actions { - display: flex; - align-items: center; - padding: 0.5rem 0; - margin-top: 1rem; -} -.content-container .lgn-actions.lgn-reverse-order { - flex-direction: row-reverse; -} -.content-container .lgn-actions .fill-space { - flex: 1; -} -.content-container .lgn-row { - display: flex; - align-items: center; - padding: 0; -} -.content-container .lgn-row.lgn-reverse-order { - flex-direction: row-reverse; -} -.content-container .lgn-row .fill-space { - flex: 1; -} -.content-container .lgn-login-profile { - margin-bottom: 0.5rem; -} -.content-container .lgn-login-profile .lgn-profile-image { - display: block; - margin: 0.5rem; -} -.content-container .lgn-login-profile .lgn-names { - border-width: 1px; - border-style: solid; - border-radius: 50vw; - display: flex; - align-items: center; -} -.content-container .lgn-login-profile .lgn-names .inline-block { - display: inline-block; - margin: 0 2px; -} -.content-container .lgn-login-profile .lgn-names .lgn-displayname { - margin: 0.5rem 1rem; -} -.content-container .lgn-login-profile .lgn-names .lgn-loginname { - min-width: 0; -} -.content-container .lgn-login-profile .lgn-names .lgn-loginname p { - margin: 0.5rem 0.5rem; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} -.content-container .lgn-left-action { - position: absolute; - left: 1rem; - top: -75px; - transform: translateY(-50%); -} -.content-container .lgn-register-options { - display: flex; - flex-direction: column; -} -.content-container .lgn-mfa-other { - display: flex; - flex-direction: column; -} -.content-container .lgn-mfa-other button { - width: 100%; - margin: 0.5rem 0; -} - -i { - font-size: 1.2rem; -} - -.lgn-account-selection { - display: flex; - flex-direction: column; - width: 100%; -} -.lgn-account-selection .lgn-account { - display: flex; - align-items: center; - border: none; - outline: none; - cursor: pointer; -} -.lgn-account-selection .lgn-account:disabled { - cursor: not-allowed; -} -.lgn-account-selection .lgn-account .left { - padding: 0.5rem 1rem; -} -.lgn-account-selection .lgn-account .lgn-names { - display: block; - margin: 0.5rem; - text-align: start; - overflow: hidden; -} -.lgn-account-selection .lgn-account .lgn-names .lgn-displayname { - font-size: 16px; - margin: 0.5rem 0; - margin-bottom: 0; - text-overflow: ellipsis; - overflow: hidden; -} -.lgn-account-selection .lgn-account .lgn-names .lgn-loginname { - font-size: 14px; - margin: 0; - text-overflow: ellipsis; - overflow: hidden; -} -.lgn-account-selection .lgn-account .lgn-names .lgn-session-state { - margin: 0.25rem 0; - border-radius: 50vw; - padding: 2px 0.5rem; - letter-spacing: 0.05em; - font-size: 12px; - white-space: nowrap; - box-shadow: 0 0 3px #0000001a; - width: fit-content; - line-height: 1rem; -} -.lgn-account-selection .lgn-account .fill-space { - flex: 1; -} -.lgn-account-selection .lgn-account i { - font-size: 1.2rem; -} -.lgn-account-selection .lgn-account i.account-add { - font-size: 1.4rem; - margin-left: 3px; -} - -.lgn-avatar { - height: 32px; - width: 32px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - text-transform: uppercase; - box-sizing: border-box; - letter-spacing: 0.05em; - font-size: 14px; - outline: none; - font-weight: bold; - overflow: hidden; -} - -.lgn-avatar .avatar-img { - height: 100%; - width: 100%; - object-fit: cover; -} - -.lgn-checkbox { - display: inline-block; - position: relative; - margin: 0 0 10px; - font-size: 14px; - line-height: 24px; - box-sizing: border-box; -} -.lgn-checkbox input[type=checkbox] { - position: absolute; - top: 4px; - left: 0; - width: 16px; - height: 16px; - opacity: 0; - z-index: 0; - box-sizing: inherit; - margin: 2px; -} -.lgn-checkbox label { - display: block; - padding: 0 0 0 30px; - cursor: pointer; - box-sizing: inherit; - font-size: 14px; - line-height: 28px; -} -.lgn-checkbox label a { - text-decoration: underline; -} -.lgn-checkbox label:before { - content: ""; - position: absolute; - top: 6px; - left: 0; - width: 16px; - height: 16px; - box-sizing: border-box; - border-radius: 2px; - transition: all 0.28s cubic-bezier(0.4, 0, 0.2, 1); - transition-property: background-color, border-color; -} -.lgn-checkbox label:after { - content: ""; - position: absolute; - top: 7px; - left: 5px; - width: 4px; - height: 10px; - transform: rotate(45deg); - transition: border-color 0.28s cubic-bezier(0.4, 0, 0.2, 1); -} - -.lgn-select, select { - background-position: right 10px center; - background-repeat: no-repeat; - background-size: auto 50%; - color: white; - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; -} -.lgn-select:not([disabled]), select:not([disabled]) { - cursor: pointer; -} -.lgn-select::-ms-expand, select::-ms-expand { - display: none; -} - -.lgn-list.lgn-policy, ul.lgn-policy { - display: flex; - flex-wrap: wrap; -} -.lgn-list.lgn-policy li, ul.lgn-policy li { - flex: 1 0 50%; -} -.lgn-list li, ul li { - display: flex; - align-items: center; - list-style: none; - margin: 4px 0; - font-style: italic; -} -.lgn-list li i, ul li i { - margin: 0 0.5rem; - font-size: 20px; -} -.lgn-list:not(.lgn-no-dots) li::before, ul:not(.lgn-no-dots) li::before { - content: "•"; - font-weight: bold; - display: inline-block; - width: 20px; - margin-left: -20px; - font-style: normal; -} -.lgn-list.lgn-no-dots, ul.lgn-no-dots { - list-style-type: none; - padding-inline-start: 0; -} - -@font-face { - font-family: Aileron; - src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 200; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 800; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 800; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 900; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 900; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 300; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 300; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Medium.ttf) format("truetype"); - font-style: normal; - font-weight: 500; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-MediumItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 500; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 900; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 900; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraBold.ttf) format("truetype"); - font-style: normal; - font-weight: 800; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraBoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 800; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraLight.ttf) format("truetype"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraLightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 200; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 300; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 300; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Medium.ttf) format("truetype"); - font-style: normal; - font-weight: 500; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-MediumItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 500; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-SemiBold.ttf) format("truetype"); - font-style: normal; - font-weight: 600; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-SemiBoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 600; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -.lgn-success-label { - border-radius: 0.5rem; - padding: 0.5rem; -} - -.lgn-mfa-options { - display: flex; - flex-direction: row; - justify-content: space-evenly; - margin: 2rem 0; -} -.lgn-mfa-options .mfa { - display: flex; - flex-direction: column; - align-items: center; - flex: 1; - padding: 0 0.5rem; -} -.lgn-mfa-options .mfa label { - display: flex; - flex-direction: column; - align-items: center; - position: relative; -} -.lgn-mfa-options .mfa label input[type=radio] { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} -.lgn-mfa-options .mfa label span { - text-align: center; -} -.lgn-mfa-options .mfa label .mfa-img { - border-width: 1px; - border-style: solid; - border-radius: 0.5rem; - padding: 1rem; - display: flex; - margin-bottom: 0.5rem; - transition: all 0.2s ease; -} - -footer { - width: 100%; - box-sizing: border-box; - background: #00000020; - min-height: 50px; - display: flex; - align-items: center; - padding: 0 1rem; -} -footer .fill-space { - flex: 1; -} -footer a { - font-size: 12px; - margin-left: 1rem; - display: block; -} -@media only screen and (min-width: 600px) { - footer { - position: fixed; - bottom: 0; - left: 0; - right: 0; - } -} -footer .watermark { - display: flex; -} -footer .watermark .powered { - font-size: 12px; - margin: auto 2px; - display: none; -} -@media only screen and (min-width: 600px) { - footer .watermark .powered { - display: inline-block; - } -} -footer .watermark .lgn-logo-watermark { - height: 40px; - min-width: 125px; - margin: auto 2px; -} - -.lgn-header { - display: flex; - position: relative; - margin: auto; - padding: 0; - max-width: 250px; - min-height: 150px; - align-items: center; - justify-content: center; -} -.lgn-header .lgn-logo { - display: block; - height: 100%; - margin: 0 auto; - max-width: 250px; - max-height: 150px; - object-fit: contain; -} - -.lgn-button, .lgn-stroked-button, .lgn-icon-button { - box-sizing: border-box; - position: relative; - cursor: pointer; - outline: none; - border: none; - -webkit-tap-highlight-color: transparent; - display: inline-block; - white-space: nowrap; - text-decoration: none; - vertical-align: baseline; - text-align: center; - margin: 0; - min-width: 64px; - line-height: 36px; - padding: 0 16px; - border-radius: 6px; - overflow: visible; - transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); -} -.lgn-button[disabled], .lgn-stroked-button[disabled], .lgn-icon-button[disabled] { - cursor: default; -} -.lgn-button::-moz-focus-inner, .lgn-stroked-button::-moz-focus-inner, .lgn-icon-button::-moz-focus-inner { - border: 0; -} - -.lgn-raised-button { - box-sizing: border-box; - position: relative; - cursor: pointer; - outline: none; - border: none; - -webkit-tap-highlight-color: transparent; - display: inline-block; - white-space: nowrap; - text-decoration: none; - vertical-align: baseline; - text-align: center; - margin: 0; - min-width: 64px; - line-height: 36px; - padding: 0 16px; - border-radius: 6px; - overflow: visible; - transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); - transform: translate3d(0, 0, 0); -} -.lgn-raised-button[disabled] { - cursor: default; -} -.lgn-raised-button::-moz-focus-inner { - border: 0; -} - -.lgn-icon-button { - padding: 0; - min-width: 0; - width: 40px; - height: 40px; - flex-shrink: 0; - line-height: 40px; - border-radius: 50%; -} -.lgn-icon-button i, .lgn-icon-button .mat-icon { - line-height: 40px; -} - -.lgn-stroked-button { - border: 1px solid currentColor; - padding: 0 15px; - line-height: 34px; -} - -.lgn-button:focus { - pointer-events: none; - transition: opacity 200ms cubic-bezier(0.35, 0, 0.25, 1), background-color 200ms cubic-bezier(0.35, 0, 0.25, 1); -} - -.lgn-button *, .lgn-stroked-button *, .lgn-raised-button * { - vertical-align: middle; -} - -input:not([type=radio]):not([type=checkbox]), -.lgn-input { - display: block; - box-sizing: border-box; - padding-inline-start: 10px; - outline: none; - display: inline-block; - text-align: start; - cursor: text; - border-radius: 4px; - transform: all 0.2 linear; - font-size: 1rem; - border-style: solid; - border-width: 1px; - height: 40px; - padding: 10px; - transition: border-color 0.2s ease-in-out; - width: 100%; - margin: 0 0 2px 0; -} -input:not([type=radio]):not([type=checkbox])::placeholder, -.lgn-input::placeholder { - font-size: 14px; - font-style: italic; -} - -select, -.lgn-select { - display: block; - box-sizing: border-box; - padding-inline-start: 10px; - outline: none; - display: inline-block; - text-align: start; - cursor: text; - border-radius: 4px; - transform: all 0.2 linear; - font-size: 1rem; - border-style: solid; - border-width: 1px; - height: 40px; - padding: 10px; - transition: border-color 0.2s ease-in-out; - width: 100%; - margin: 0 0 2px 0; -} -select::placeholder, -.lgn-select::placeholder { - font-size: 14px; - font-style: italic; -} - -.lgn-suffix-wrapper { - position: relative; -} -.lgn-suffix-wrapper [lgnSuffix] { - position: absolute; - right: 0.5rem; - top: 9px; - height: inherit; - vertical-align: middle; - max-width: 150px; - overflow-x: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.lgn-label { - display: block; - font-size: 12px; - transition: color 0.2s ease; - margin: 0 0 2px 0; - font-weight: 400; -} -.lgn-label * { - font-size: 12px; -} - -@keyframes ripple { - 0% { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0); - } - 50% { - box-shadow: 0 0 0 15px rgba(0, 0, 0, 0.1); - } - 100% { - box-shadow: 0 0 0 15px rgba(0, 0, 0, 0); - } -} -.lgn-radio { - outline: none; - margin: 16px 0; - display: inline-block; -} -.lgn-radio.block { - display: block; -} -.lgn-radio label { - display: inline-block; - height: 20px; - position: relative; - padding: 0 0 0 30px; - margin-bottom: 0; - cursor: pointer; - vertical-align: middle; - padding-top: 2px; - outline: none; - font-size: 14px; - line-height: 16px; -} -.lgn-radio label::before, .lgn-radio label::after { - position: absolute; - content: ""; - border-radius: 50%; - transition: all 0.3s ease; - transition-property: transform, border-color; -} -.lgn-radio label::before { - left: 0; - top: 0; - width: 20px; - height: 20px; - border-width: 2px; - border-style: solid; -} -.lgn-radio label::after { - top: 5px; - left: 5px; - width: 10px; - height: 10px; - transform: scale(0); -} -.lgn-radio input[type=radio] { - display: block; - opacity: 0; - margin: 0; - width: 0; - height: 0; - outline: none; -} -.lgn-radio input[type=radio]:checked + label::before { - animation: ripple 0.2s linear forwards; -} -.lgn-radio input[type=radio]:checked + label::after { - transform: scale(1); -} -.lgn-radio input[type=radio]:focus + label { - opacity: 1; -} -.lgn-radio input[type=radio]:disabled + label { - cursor: not-allowed; - font-style: italic; -} -.lgn-radio input[type=radio]:disabled:focus { - opacity: 0; -} -.lgn-radio *, -.lgn-radio *::before, -.lgn-radio *::after { - box-sizing: border-box; -} - -a { - text-decoration: none; - cursor: pointer; - margin: 2px 0; -} -a.block { - display: block; -} -a.sub-formfield-link { - margin: 10px 0; - text-decoration: underline; -} - -.lgn-idp { - display: block; - margin: 0.5rem 0; - box-sizing: border-box; - display: flex; - align-items: center; - position: relative; - padding: 0 1px; - border-radius: 0.5rem; - border-width: 1px; - border-style: solid; -} -.lgn-idp span.logo { - height: 46px; - width: 46px; -} -.lgn-idp span.provider-name { - line-height: 36px; - position: absolute; - left: 50%; - transform: translateX(-50%); -} -.lgn-idp.google span.logo { - height: 46px; - width: 46px; - background-image: url("../../../images/idp/google.png"); - background-size: 25px; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; -} -.lgn-idp.github span.logo { - height: 46px; - width: 46px; - background-image: url("../../../images/idp/github.png"); - background-size: 25px; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; -} -.lgn-idp.gitlab span.logo { - height: 46px; - width: 46px; - background-image: url("../../../images/idp/gitlab.png"); - background-size: 100%; - background-position: center; - background-repeat: no-repeat; - border-radius: 5px; -} - -.lgn-error { - display: flex; - align-items: center; - outline: none; -} -.lgn-error i { - margin-right: 0.5rem; - font-size: 1.5rem; -} - -#wa-error { - flex-direction: column; -} - -.lgn-qrcode { - display: block; - margin: auto; - margin: 1rem 0; - margin-bottom: 1.5rem; -} -.lgn-qrcode svg { - margin: auto; - display: block; - border-radius: 0.5rem; -} - -.lgn-max-width-wrapper { - max-width: 440px; - margin: auto; - margin-top: 50px; - margin-bottom: 50px; - display: block; -} -@media only screen and (min-width: 600px) { - .lgn-max-width-wrapper { - margin-top: 100px; - } -} - -.content-container { - position: relative; - display: block; - margin: 0 auto 0 auto; - padding: 20px; - width: 100%; - box-sizing: border-box; -} -.content-container .lgn-head h1 { - text-align: center; -} -.content-container .lgn-head p { - text-align: center; -} -.content-container .lgn-actions { - display: flex; - align-items: center; - padding: 0.5rem 0; - margin-top: 1rem; -} -.content-container .lgn-actions.lgn-reverse-order { - flex-direction: row-reverse; -} -.content-container .lgn-actions .fill-space { - flex: 1; -} -.content-container .lgn-row { - display: flex; - align-items: center; - padding: 0; -} -.content-container .lgn-row.lgn-reverse-order { - flex-direction: row-reverse; -} -.content-container .lgn-row .fill-space { - flex: 1; -} -.content-container .lgn-login-profile { - margin-bottom: 0.5rem; -} -.content-container .lgn-login-profile .lgn-profile-image { - display: block; - margin: 0.5rem; -} -.content-container .lgn-login-profile .lgn-names { - border-width: 1px; - border-style: solid; - border-radius: 50vw; - display: flex; - align-items: center; -} -.content-container .lgn-login-profile .lgn-names .inline-block { - display: inline-block; - margin: 0 2px; -} -.content-container .lgn-login-profile .lgn-names .lgn-displayname { - margin: 0.5rem 1rem; -} -.content-container .lgn-login-profile .lgn-names .lgn-loginname { - min-width: 0; -} -.content-container .lgn-login-profile .lgn-names .lgn-loginname p { - margin: 0.5rem 0.5rem; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} -.content-container .lgn-left-action { - position: absolute; - left: 1rem; - top: -75px; - transform: translateY(-50%); -} -.content-container .lgn-register-options { - display: flex; - flex-direction: column; -} -.content-container .lgn-mfa-other { - display: flex; - flex-direction: column; -} -.content-container .lgn-mfa-other button { - width: 100%; - margin: 0.5rem 0; -} - -i { - font-size: 1.2rem; -} - -.lgn-account-selection { - display: flex; - flex-direction: column; - width: 100%; -} -.lgn-account-selection .lgn-account { - display: flex; - align-items: center; - border: none; - outline: none; - cursor: pointer; -} -.lgn-account-selection .lgn-account:disabled { - cursor: not-allowed; -} -.lgn-account-selection .lgn-account .left { - padding: 0.5rem 1rem; -} -.lgn-account-selection .lgn-account .lgn-names { - display: block; - margin: 0.5rem; - text-align: start; - overflow: hidden; -} -.lgn-account-selection .lgn-account .lgn-names .lgn-displayname { - font-size: 16px; - margin: 0.5rem 0; - margin-bottom: 0; - text-overflow: ellipsis; - overflow: hidden; -} -.lgn-account-selection .lgn-account .lgn-names .lgn-loginname { - font-size: 14px; - margin: 0; - text-overflow: ellipsis; - overflow: hidden; -} -.lgn-account-selection .lgn-account .lgn-names .lgn-session-state { - margin: 0.25rem 0; - border-radius: 50vw; - padding: 2px 0.5rem; - letter-spacing: 0.05em; - font-size: 12px; - white-space: nowrap; - box-shadow: 0 0 3px #0000001a; - width: fit-content; - line-height: 1rem; -} -.lgn-account-selection .lgn-account .fill-space { - flex: 1; -} -.lgn-account-selection .lgn-account i { - font-size: 1.2rem; -} -.lgn-account-selection .lgn-account i.account-add { - font-size: 1.4rem; - margin-left: 3px; -} - -.lgn-avatar { - height: 32px; - width: 32px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - text-transform: uppercase; - box-sizing: border-box; - letter-spacing: 0.05em; - font-size: 14px; - outline: none; - font-weight: bold; - overflow: hidden; -} - -.lgn-avatar .avatar-img { - height: 100%; - width: 100%; - object-fit: cover; -} - -.lgn-checkbox { - display: inline-block; - position: relative; - margin: 0 0 10px; - font-size: 14px; - line-height: 24px; - box-sizing: border-box; -} -.lgn-checkbox input[type=checkbox] { - position: absolute; - top: 4px; - left: 0; - width: 16px; - height: 16px; - opacity: 0; - z-index: 0; - box-sizing: inherit; - margin: 2px; -} -.lgn-checkbox label { - display: block; - padding: 0 0 0 30px; - cursor: pointer; - box-sizing: inherit; - font-size: 14px; - line-height: 28px; -} -.lgn-checkbox label a { - text-decoration: underline; -} -.lgn-checkbox label:before { - content: ""; - position: absolute; - top: 6px; - left: 0; - width: 16px; - height: 16px; - box-sizing: border-box; - border-radius: 2px; - transition: all 0.28s cubic-bezier(0.4, 0, 0.2, 1); - transition-property: background-color, border-color; -} -.lgn-checkbox label:after { - content: ""; - position: absolute; - top: 7px; - left: 5px; - width: 4px; - height: 10px; - transform: rotate(45deg); - transition: border-color 0.28s cubic-bezier(0.4, 0, 0.2, 1); -} - -.lgn-select, select { - background-position: right 10px center; - background-repeat: no-repeat; - background-size: auto 50%; - color: white; - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; -} -.lgn-select:not([disabled]), select:not([disabled]) { - cursor: pointer; -} -.lgn-select::-ms-expand, select::-ms-expand { - display: none; -} - -.lgn-list.lgn-policy, ul.lgn-policy { - display: flex; - flex-wrap: wrap; -} -.lgn-list.lgn-policy li, ul.lgn-policy li { - flex: 1 0 50%; -} -.lgn-list li, ul li { - display: flex; - align-items: center; - list-style: none; - margin: 4px 0; - font-style: italic; -} -.lgn-list li i, ul li i { - margin: 0 0.5rem; - font-size: 20px; -} -.lgn-list:not(.lgn-no-dots) li::before, ul:not(.lgn-no-dots) li::before { - content: "•"; - font-weight: bold; - display: inline-block; - width: 20px; - margin-left: -20px; - font-style: normal; -} -.lgn-list.lgn-no-dots, ul.lgn-no-dots { - list-style-type: none; - padding-inline-start: 0; -} - -@font-face { - font-family: Aileron; - src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 200; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 800; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 800; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 900; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 900; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 300; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 300; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Medium.ttf) format("truetype"); - font-style: normal; - font-weight: 500; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-MediumItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 500; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 900; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 900; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraBold.ttf) format("truetype"); - font-style: normal; - font-weight: 800; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraBoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 800; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraLight.ttf) format("truetype"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraLightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 200; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 300; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 300; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Medium.ttf) format("truetype"); - font-style: normal; - font-weight: 500; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-MediumItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 500; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-SemiBold.ttf) format("truetype"); - font-style: normal; - font-weight: 600; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-SemiBoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 600; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -.lgn-success-label { - border-radius: 0.5rem; - padding: 0.5rem; -} - -.lgn-mfa-options { - display: flex; - flex-direction: row; - justify-content: space-evenly; - margin: 2rem 0; -} -.lgn-mfa-options .mfa { - display: flex; - flex-direction: column; - align-items: center; - flex: 1; - padding: 0 0.5rem; -} -.lgn-mfa-options .mfa label { - display: flex; - flex-direction: column; - align-items: center; - position: relative; -} -.lgn-mfa-options .mfa label input[type=radio] { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} -.lgn-mfa-options .mfa label span { - text-align: center; -} -.lgn-mfa-options .mfa label .mfa-img { - border-width: 1px; - border-style: solid; - border-radius: 0.5rem; - padding: 1rem; - display: flex; - margin-bottom: 0.5rem; - transition: all 0.2s ease; -} - -@font-face { - font-family: Aileron; - src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 200; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 800; -} -@font-face { - font-family: Lato; - src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 800; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 900; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 900; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 300; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 300; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Medium.ttf) format("truetype"); - font-style: normal; - font-weight: 500; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-MediumItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 500; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Roboto; - src: url(../../../fonts/Roboto/Roboto-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Black.ttf) format("truetype"); - font-style: normal; - font-weight: 900; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-BlackItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 900; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraBold.ttf) format("truetype"); - font-style: normal; - font-weight: 800; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraBoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 800; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraLight.ttf) format("truetype"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ExtraLightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 200; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Light.ttf) format("truetype"); - font-style: normal; - font-weight: 300; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-LightItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 300; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Medium.ttf) format("truetype"); - font-style: normal; - font-weight: 500; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-MediumItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 500; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-SemiBold.ttf) format("truetype"); - font-style: normal; - font-weight: 600; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-SemiBoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 600; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-Thin.ttf) format("truetype"); - font-style: normal; - font-weight: 100; -} -@font-face { - font-family: Raleway; - src: url(../../../fonts/Raleway/Raleway-ThinItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 100; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 700; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-BoldItalic.ttf) format("truetype"); - font-style: italic; - font-weight: 700; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Italic.ttf) format("truetype"); - font-style: italic; - font-weight: 400; -} -@font-face { - font-family: PTSans; - src: url(../../../fonts/PT_Sans/PTSans-Regular.ttf) format("truetype"); - font-style: normal; - font-weight: 400; -} -.lgn-max-width-wrapper { - max-width: 440px; - margin: auto; - margin-top: 50px; - margin-bottom: 50px; - display: block; -} -@media only screen and (min-width: 600px) { - .lgn-max-width-wrapper { - margin-top: 100px; - } -} - -.content-container { - position: relative; - display: block; - margin: 0 auto 0 auto; - padding: 20px; - width: 100%; - box-sizing: border-box; -} -.content-container .lgn-head h1 { - text-align: center; -} -.content-container .lgn-head p { - text-align: center; -} -.content-container .lgn-actions { - display: flex; - align-items: center; - padding: 0.5rem 0; - margin-top: 1rem; -} -.content-container .lgn-actions.lgn-reverse-order { - flex-direction: row-reverse; -} -.content-container .lgn-actions .fill-space { - flex: 1; -} -.content-container .lgn-row { - display: flex; - align-items: center; - padding: 0; -} -.content-container .lgn-row.lgn-reverse-order { - flex-direction: row-reverse; -} -.content-container .lgn-row .fill-space { - flex: 1; -} -.content-container .lgn-login-profile { - margin-bottom: 0.5rem; -} -.content-container .lgn-login-profile .lgn-profile-image { - display: block; - margin: 0.5rem; -} -.content-container .lgn-login-profile .lgn-names { - border-width: 1px; - border-style: solid; - border-radius: 50vw; - display: flex; - align-items: center; -} -.content-container .lgn-login-profile .lgn-names .inline-block { - display: inline-block; - margin: 0 2px; -} -.content-container .lgn-login-profile .lgn-names .lgn-displayname { - margin: 0.5rem 1rem; -} -.content-container .lgn-login-profile .lgn-names .lgn-loginname { - min-width: 0; -} -.content-container .lgn-login-profile .lgn-names .lgn-loginname p { - margin: 0.5rem 0.5rem; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} -.content-container .lgn-left-action { - position: absolute; - left: 1rem; - top: -75px; - transform: translateY(-50%); -} -.content-container .lgn-register-options { - display: flex; - flex-direction: column; -} -.content-container .lgn-mfa-other { - display: flex; - flex-direction: column; -} -.content-container .lgn-mfa-other button { - width: 100%; - margin: 0.5rem 0; -} - -i { - font-size: 1.2rem; -} - -.lgn-register .double-col { - display: flex; - flex-wrap: wrap; - margin: 0 -0.5rem; -} -.lgn-register .double-col .lgn-field { - margin: 0 0.5rem; - flex: 1; - box-sizing: border-box; - margin-bottom: 0.5rem; -} -.lgn-register .lgn-field { - margin-bottom: 0.5rem; -} - -.lgn-header { - display: flex; - position: relative; - margin: auto; - padding: 0; - max-width: 250px; - min-height: 150px; - align-items: center; - justify-content: center; -} -.lgn-header .lgn-logo { - display: block; - height: 100%; - margin: 0 auto; - max-width: 250px; - max-height: 150px; - object-fit: contain; -} - -@keyframes shake { - 10%, 90% { - transform: translate3d(-1px, 0, 0); - } - 20%, 80% { - transform: translate3d(2px, 0, 0); - } - 30%, 50%, 70% { - transform: translate3d(-4px, 0, 0); - } - 40%, 60% { - transform: translate3d(4px, 0, 0); - } -} -[shake] { - animation: shake 0.8s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; - transform: translate3d(0, 0, 0); -} - -h1, .lgn-headline, .lgn-typography h1 { - font: 400 24px/32px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; - margin: 0 0 16px; -} - -h2, .lgn-title, .lgn-typography h2 { - font: 500 20px/32px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; - margin: 0 0 16px; -} - -h3, .lgn-subheading-2, .lgn-typography h3 { - font: 400 16px/28px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; - margin: 0 0 16px; -} - -h4, .lgn-subheading-1, .lgn-typography h4 { - font: 400 15px/24px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; - margin: 0 0 16px; -} - -.lgn-body-strong, .lgn-body-2 { - font: 500 14px/24px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; -} - -p, .lgn-body, .lgn-body-1, .lgn-typography { - font: 400 14px/20px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; -} -p p, .lgn-body p, .lgn-body-1 p, .lgn-typography p { - margin: 0 0 12px; -} - -button, .lgn-button, .lgn-raised-button, .lgn-stroked-button { - font: 500 14px/36px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; -} - -span { - font: 400 14px/20px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; -} - -a, .lgn-a { - font: 400 14px/20px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; -} - -small .lgn-small, .lgn-caption { - font: 400 12px/20px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; -} - -label, .lgn-label, .lgn-typography .lgn-label, .lgn-typography label { - font: 400 12px/20px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; - margin: 0 0 2px 0; -} - -.lgn-display-4, .lgn-typography .lgn-display-4 { - font: 300 112px/112px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: -0.05em; - margin: 0 0 56px; -} - -.lgn-display-3, .lgn-typography .lgn-display-3 { - font: 400 56px/56px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: -0.02em; - margin: 0 0 64px; -} - -.lgn-display-2, .lgn-typography .lgn-display-2 { - font: 400 45px/48px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: -0.005em; - margin: 0 0 64px; -} - -.lgn-display-1, .lgn-typography .lgn-display-1 { - font: 400 34px/40px serif; - font-family: var(--zitadel-font-family), -apple-system, BlinkMacSystemFont, sans-serif; - letter-spacing: normal; - margin: 0 0 64px; -} - -.lgn-app-background { - background-color: var(--zitadel-color-background); - color: var(--zitadel-color-text); -} - -.lgn-theme-loaded-marker { - display: none; -} - -.lgn-logo { - background-position: auto; - background-size: contain; -} - -.lgn-button, -.lgn-stroked-button, -.lgn-icon-button { - color: inherit; - background: transparent; -} -.lgn-button.lgn-primary, -.lgn-stroked-button.lgn-primary, -.lgn-icon-button.lgn-primary { - color: var(--zitadel-color-primary); -} -.lgn-button.lgn-accent, -.lgn-stroked-button.lgn-accent, -.lgn-icon-button.lgn-accent { - color: var(--zitadel-color-primary); -} -.lgn-button.lgn-warn, -.lgn-stroked-button.lgn-warn, -.lgn-icon-button.lgn-warn { - color: var(--zitadel-color-primary); -} -.lgn-button.lgn-primary[disabled], .lgn-button.lgn-accent[disabled], .lgn-button.lgn-warn[disabled], .lgn-button[disabled][disabled], -.lgn-stroked-button.lgn-primary[disabled], -.lgn-stroked-button.lgn-accent[disabled], -.lgn-stroked-button.lgn-warn[disabled], -.lgn-stroked-button[disabled][disabled], -.lgn-icon-button.lgn-primary[disabled], -.lgn-icon-button.lgn-accent[disabled], -.lgn-icon-button.lgn-warn[disabled], -.lgn-icon-button[disabled][disabled] { - color: var(--zitadel-color-button-disabled); -} - -.lgn-stroked-button:hover, -.lgn-stroked-button:focus { - background: var(--zitadel-color-stroked-button-hover-background); -} - -.lgn-stroked-button:active { - background: var(--zitadel-color-stroked-button-active-background); -} - -.lgn-button:focus, -.lgn-raised-button:focus { - box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 5px 8px 0px rgba(0, 0, 0, 0.14), 0px 1px 14px 0px rgba(0, 0, 0, 0.12); - background: var(--zitadel-color-background); -} - -.lgn-stroked-button:not([disabled]) { - border-color: var(--zitadel-color-divider); -} - -.lgn-button.lgn-primary { - color: var(--zitadel-color-primary); -} -.lgn-button.lgn-accent { - color: var(--zitadel-color-primary); -} -.lgn-button.lgn-warn { - color: var(--zitadel-color-primary); -} -.lgn-button.lgn-primary[disabled], .lgn-button.lgn-accent[disabled], .lgn-button.lgn-warn[disabled], .lgn-button[disabled][disabled] { - color: var(--zitadel-color-button-disabled); -} -.lgn-button:hover { - background-color: rgba(var(--zitadel-color-primary-rgb), 0.1); -} -.lgn-button:focus { - background-color: rgba(var(--zitadel-color-primary-rgb), 0.2); -} -.lgn-button:active { - background-color: rgba(var(--zitadel-color-primary-rgb), 0.25); -} - -.lgn-raised-button { - color: var(--zitadel-color-text); - background-color: var(--zitadel-color-raised-button-background); -} -.lgn-raised-button.lgn-primary { - color: var(--zitadel-color-primary-contrast); -} -.lgn-raised-button.lgn-accent { - color: var(--zitadel-color-primary-contrast); -} -.lgn-raised-button.lgn-warn { - color: var(--zitadel-color-primary-contrast); -} -.lgn-raised-button.lgn-primary[disabled], .lgn-raised-button.lgn-accent[disabled], .lgn-raised-button.lgn-warn[disabled], .lgn-raised-button[disabled][disabled] { - color: var(--zitadel-color-button-disabled); -} -.lgn-raised-button.lgn-primary { - background-color: var(--zitadel-color-primary); -} -.lgn-raised-button.lgn-accent { - background-color: var(--zitadel-color-primary); -} -.lgn-raised-button.lgn-warn { - background-color: var(--zitadel-color-primary); -} -.lgn-raised-button.lgn-primary[disabled], .lgn-raised-button.lgn-accent[disabled], .lgn-raised-button.lgn-warn[disabled], .lgn-raised-button[disabled][disabled] { - background-color: var(--zitadel-color-button-disabled-background); -} -.lgn-raised-button:active { - background-color: var(--zitadel-color-raised-button-active-background); -} - -.lgn-button, -.lgn-stroked-button { - box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12); -} - -.lgn-raised-button { - box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); -} -.lgn-raised-button:not([disabled]):active { - box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 5px 8px 0px rgba(0, 0, 0, 0.14), 0px 1px 14px 0px rgba(0, 0, 0, 0.12); -} -.lgn-raised-button[disabled] { - box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12); -} - -.lgn-input:not([disabled]), -select:not([disabled]), -.lgn-select:not([disabled]) { - border-color: var(--zitadel-color-input-border); -} - -.lgn-input, -select, -.lgn-select { - color: var(--zitadel-color-text); - background-color: var(--zitadel-color-input-background); -} -.lgn-input:hover, -select:hover, -.lgn-select:hover { - border-color: var(--zitadel-color-input-border-hover); -} -.lgn-input:active, -select:active, -.lgn-select:active { - border-color: var(--zitadel-color-input-border-active); -} -.lgn-input:focus, -select:focus, -.lgn-select:focus { - border-color: var(--zitadel-color-input-border-active); -} -.lgn-input.lgn-touched[color=warn], -select.lgn-touched[color=warn], -.lgn-select.lgn-touched[color=warn] { - border-color: var(--zitadel-color-warn); -} - -.lgn-input::placeholder, -select::placeholder, -.lgn-select::placeholder { - color: var(--zitadel-color-input-placeholder); -} - -label::before { - border-color: var(--zitadel-color-input-border); -} -label::after { - background: var(--zitadel-color-primary); -} - -input[type=radio] { - opacity: 0; -} -input[type=radio]:checked + label::before { - border-color: var(--zitadel-color-primary); -} -input[type=radio]:focus + label { - opacity: 1; - outline: none; -} -input[type=radio]:disabled + label::before { - border-color: var(--zitadel-color-button-disabled-background); -} -input[type=radio]:disabled:checked + label::before { - color: var(--zitadel-color-button-selected-background); -} -input[type=radio]:disabled:checked + label::after { - background: var(--zitadel-color-button-disabled-selected-background); -} -input[type=radio]:disabled:focus { - opacity: 0; -} - -input[type=checkbox] { - position: absolute; - top: 4px; - left: 0; - width: 16px; - height: 16px; - opacity: 0; - z-index: 0; -} - -.lgn-checkbox label:before { - background-color: transparent; - border: 2px solid var(--zitadel-color-input-border); -} -.lgn-checkbox label:after { - border-bottom: 2px solid transparent; - border-right: 2px solid transparent; - background: transparent; -} - -input[type=checkbox]:checked + label:before { - background-color: var(--zitadel-color-primary); - border-color: var(--zitadel-color-primary); -} -input[type=checkbox]:checked + label:after { - border-color: var(--zitadel-color-primary-contrast); -} - -.lgn-label { - color: var(--zitadel-color-label); -} - -footer { - background-color: var(--zitadel-color-footer-background); - border-top: 1px solid var(--zitadel-color-footer-line); - backdrop-filter: blur(10px); -} -@-moz-document url-prefix() { - footer { - background-color: var(--zitadel-color-footer-background-mozilla); - backdrop-filter: none; - } -} -footer a { - color: var(--zitadel-color-text-500); -} -footer .lgn-logo-watermark { - background: var(--zitadel-logo-powered-by) no-repeat; - background-position: center; - background-size: contain; -} - -a:not(.lgn-stroked-button):not(.lgn-button):not(.lgn-raised-button):not(.lgn-idp) { - color: var(--zitadel-color-text-500); -} -a:not(.lgn-stroked-button):not(.lgn-button):not(.lgn-raised-button):not(.lgn-idp):hover, a:not(.lgn-stroked-button):not(.lgn-button):not(.lgn-raised-button):not(.lgn-idp):active { - color: var(--zitadel-color-primary-500); -} - -.lgn-error { - color: var(--zitadel-color-warn); -} - -.lgn-qrcode svg { - background: var(--zitadel-color-qr-background); -} -.lgn-qrcode svg rect.color { - fill: var(--zitadel-color-qr); -} -.lgn-qrcode svg rect.bg-color { - fill: var(--zitadel-color-qr-background); -} - -.lgn-error .lgn-error-message { - color: var(--zitadel-color-warn); -} - -.lgn-login-profile .lgn-names { - border-color: var(--zitadel-color-divider); -} - -.lgn-account-selection { - display: flex; - flex-direction: column; - width: 100%; -} -.lgn-account-selection .lgn-account { - color: inherit; - background: transparent; - box-shadow: inset 0 -1px var(--zitadel-color-footer-line); -} -.lgn-account-selection .lgn-account:hover { - background-color: var(--zitadel-color-account-selector-hover); -} -.lgn-account-selection .lgn-account:focus { - background-color: var(--zitadel-color-account-selector-active); -} -.lgn-account-selection .lgn-account:active { - background-color: var(--zitadel-color-account-selector-active); -} -.lgn-account-selection .lgn-account .lgn-loginname { - font-size: 14px; - color: var(--zitadel-color-label); -} -.lgn-account-selection .lgn-account .lgn-session-state { - color: var(--zitadel-color-label); -} -.lgn-account-selection .lgn-account .lgn-session-state.i0 { - color: var(--zitadel-color-state-success-font); - background: var(--zitadel-color-state-success-background); -} -.lgn-account-selection .lgn-account .lgn-session-state.i1 { - color: var(--zitadel-color-state-warn-font); - background: var(--zitadel-color-state-warn-background); -} - -.lgn-avatar:not(.transparent).lgn-primary { - background-color: var(--zitadel-color-primary); -} -.lgn-avatar:not(.transparent).lgn-accent { - background-color: var(--zitadel-color-primary); -} -.lgn-avatar:not(.transparent).lgn-warn { - background-color: var(--zitadel-color-primary); -} -.lgn-avatar:not(.transparent).lgn-primary[disabled], .lgn-avatar:not(.transparent).lgn-accent[disabled], .lgn-avatar:not(.transparent).lgn-warn[disabled], .lgn-avatar:not(.transparent)[disabled][disabled] { - background-color: var(--itadel-color-button-disabled-background); -} - -.lgn-select, select { - background-image: var(--zitadel-icon-select); -} - -.lgn-list li::before, -ul li::before { - color: var(--zitadel-color-primary); -} -.lgn-list li i.lgn-warn, -ul li i.lgn-warn { - color: var(--zitadel-color-warn); -} -.lgn-list li i.lgn-valid, -ul li i.lgn-valid { - color: var(--zitadel-color-success); -} - -.lgn-idp { - border-color: var(--zitadel-color-divider); - color: var(--zitadel-color-text-500); -} -.lgn-idp:hover { - box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12); -} -.lgn-idp:not([disabled]):active { - box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); -} -.lgn-idp.google { - color: var(--zitadel-color-google-text); - background-color: var(--zitadel-color-google-background); -} -.lgn-idp.github { - color: var(--zitadel-color-github-text); - background-color: var(--zitadel-color-github-background); -} -.lgn-idp.gitlab { - color: var(--zitadel-color-gitlab-text); - background-color: var(--zitadel-color-gitlab-background); -} - -.lgn-idp-providers .lgn-idp-desc { - color: var(--zitadel-color-label); -} - -.lgn-success-label { - color: var(--zitadel-color-success); - background-color: var(--zitadel-color-success-background); -} - -.lgn-mfa-options .mfa label input[type=radio]:hover + .mfa-img, .lgn-mfa-options .mfa label input[type=radio]:focus + .mfa-img { - background-color: var(--zitadel-color-card-hover); - border-color: var(--zitadel-color-input-border-hover); -} -.lgn-mfa-options .mfa label .mfa-img { - border: 1px solid var(--zitadel-color-input-border); -} -.lgn-mfa-options .mfa label input[type=radio]:checked + .mfa-img { - background-color: var(--zitadel-color-card-hover); - border: 1px solid var(--zitadel-color-input-border-active); - box-shadow: 0 0 0 2px var(--zitadel-color-input-border-active); -} - -/*# sourceMappingURL=zitadel.css.map */ diff --git a/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css.map b/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css.map deleted file mode 100644 index 0fa129cf1..000000000 --- a/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sourceRoot":"","sources":["../../scss/styles/vars.scss","../../scss/main.scss","../../scss/styles/footer/footer.scss","../../scss/styles/header/header.scss","../../scss/styles/button/button.scss","../../scss/styles/button/button_base.scss","../../scss/styles/input/input.scss","../../scss/styles/input/input_base.scss","../../scss/styles/label/label.scss","../../scss/styles/label/label_base.scss","../../scss/styles/radio/radio_base.scss","../../scss/styles/radio/radio.scss","../../scss/styles/a/a.scss","../../scss/styles/identity_provider/identity_provider.scss","../../scss/styles/identity_provider/identity_provider_base.scss","../../scss/styles/error/error.scss","../../scss/styles/qrcode/qrcode.scss","../../scss/styles/container/container.scss","../../scss/styles/account_selection/account_selection.scss","../../scss/styles/avatar/avatar.scss","../../scss/styles/checkbox/checkbox.scss","../../scss/styles/checkbox/checkbox_base.scss","../../scss/styles/select/select.scss","../../scss/styles/select/select_base.scss","../../scss/styles/list/list_base.scss","../../scss/styles/typography/faces/ailerons_font_faces.scss","../../scss/styles/typography/faces/lato_font_faces.scss","../../scss/styles/typography/faces/roboto_font_faces.scss","../../scss/styles/typography/faces/raleway_font_faces.scss","../../scss/styles/typography/faces/pt_sans_font_faces.scss","../../scss/styles/success_label/success_label.scss","../../scss/styles/mfa/mfa.scss","../../scss/styles/mfa/mfa_base.scss","../../scss/styles/register/register.scss","../../scss/styles/animations.scss","../../scss/styles/typography/typography.scss","../../scss/styles/core/core.scss","../../scss/styles/header/header_theme.scss","../../scss/styles/button/button_theme.scss","../../scss/styles/elevation/elevation.scss","../../scss/styles/input/input_theme.scss","../../scss/styles/radio/radio_theme.scss","../../scss/styles/checkbox/checkbox_theme.scss","../../scss/styles/label/label_theme.scss","../../scss/styles/footer/footer_theme.scss","../../scss/styles/a/a_theme.scss","../../scss/styles/error/error_theme.scss","../../scss/styles/qrcode/qrcode_theme.scss","../../scss/styles/container/container_theme.scss","../../scss/styles/account_selection/account_selection_theme.scss","../../scss/styles/avatar/avatar_theme.scss","../../scss/styles/select/select_theme.scss","../../scss/styles/list/list_theme.scss","../../scss/styles/identity_provider/identity_provider_theme.scss","../../scss/styles/success_label/success_label_theme.scss","../../scss/styles/mfa/mfa_theme.scss"],"names":[],"mappings":";AAAA;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;AAAA;AAAA;EAIA;EAEA;EACA;EACA;EACA;AAAA;AAAA;EAGA;EACA;EACA;EACA;AAAA;AAAA;EAIA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EAEA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;AAAA;AAAA;EAIA;EAEA;EACA;EACA;EACA;AAAA;AAAA;EAGA;EACA;EACA;EACA;AAAA;AAAA;AAIA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;;AC/NF;EACI;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;;AAIR;EACI;;;AAGJ;EACI;;;AChBJ;EACE;EACA;EACA;EACA,YAPc;EAQd;EACA;EACA,SATe;;AAWf;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EAnBF;IAoBI;IACA;IACA;IACA;;;AAGF;EACE;;AAEA;EACE;EACA;EACA;;AAEA;EALF;IAMI;;;AAIJ;EACE;EACA;EACA;;;AC3CN;EACE;EACA;EACA,QALkB;EAMlB,SAPmB;EAQnB;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;;;ACjBJ;ECkBE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EAGA,QAjCkB;EAkClB,WAnCqB;EAoCrB,aAlCuB;EAmCvB,SAtCmB;EAuCnB,eAnCyB;EAqCzB;EACA;;AAEA;EACE;;AAGF;EACE;;;AD3CJ;ECcE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EAGA,QAjCkB;EAkClB,WAnCqB;EAoCrB,aAlCuB;EAmCvB,SAtCmB;EAuCnB,eAnCyB;EAqCzB;EACA;EAgBA;;AAdA;EACE;;AAGF;EACE;;;ADvCJ;EACE;EACA;EACA,OCCqB;EDArB;EACA;EACA,aCFqB;EDGrB,eCF8B;;ADI9B;EACE,aCJ0B;;;ADQ9B;EACE;EACA,SCf2B;EDgB3B,aCjB+B;;;ADoBjC;EACE;EACA,YC3B4B;;;AD+B5B;EACE;;;AEnCJ;AAAA;ECOI;EACA;EACA,sBAXsB;EAYtB;EACA;EACA;EACA;EACA,eAZsB;EAatB;EACA;EACA;EACA,cAfqB;EAgBrB,QAlBoB;EAmBpB,SArBgB;EAsBhB;EACA;EACA,QAvBe;;AAyBf;AAAA;EACI,WAtB0B;EAuB1B;;;ADrBR;AAAA;ECCI;EACA;EACA,sBAXsB;EAYtB;EACA;EACA;EACA;EACA,eAZsB;EAatB;EACA;EACA;EACA,cAfqB;EAgBrB,QAlBoB;EAmBpB,SArBgB;EAsBhB;EACA;EACA,QAvBe;;AAyBf;AAAA;EACI,WAtB0B;EAuB1B;;;ADhBR;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AEvBJ;ECGI;EACA,WANkB;EAOlB;EACA,QAPe;EAQf,aAPoB;;ADGtB;EACE;;;AEEJ;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;;AChBJ;EDqBE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA,QA9Ba;EA+Bb;EACA,SA7BsB;EA8BtB;EACA;EACA;EACA;EACA;EACA,WAzCkB;EA0ClB;;AAEA;EAEE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA,OArDW;EAsDX,QAtDW;EAuDX;EACA;;AAGF;EACE;EACA;EACA,OA7DmB;EA8DnB,QA9DmB;EA+DnB;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAOA;EACE;EACA;;AAGF;EACE;;AAKN;AAAA;AAAA;EAGE;;;AE7GJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;;ACTJ;ECOI;EACA,QAVa;EAWb;EACA;EACA;EACA;EACA,SAdc;EAed,eAboB;EAcpB;EACA;;AAEA;EACI;EACA;;AAGJ;EACI,aAxB4B;EAyB5B;EACA;EACA;;AAIA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AChEZ;EACI;EACA;EACA;;AACA;EACI;EACA;;;AAIR;EACI;;;ACXJ;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;;ACHR;EACE,WAPwB;EAQxB;EACA;EACA,eAN4B;EAO5B;;AAEA;EAPF;IAQI,YAXuB;;;;AAe3B;EACE;EACA;EACA,QAnBqB;EAoBrB,SArBsB;EAsBtB;EACA;;AAGE;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;EACA;;AAIA;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;;AAIA;EACE;;AAGF;EACE;;AAIJ;EACE;;AAEA;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;EACA;EACA;EACA;;AAMR;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;;AAKN;EACE;;;AC7HF;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIJ;EACE;;AAGF;EACE;;AAEA;EACE;EACA;;;AC/DR;EACI,QAHc;EAId,OAJc;EAKd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;;;ACrBJ;ECCE;EACA;EACA;EACA,WANuB;EAOvB;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA,WA5BqB;EA6BrB;;AAEA;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACtDN;ECCE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;;ACfA;EACI;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAIR;EACI;EACA;;;ACpCR;EACI;EACA;;ACFJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AC7DJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;ACzEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AC9GJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;ACtBJ;EACE;EACA;;;ACFF;ECDE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;A9BlCR;EACE;EACA;EACA;EACA,YAPc;EAQd;EACA;EACA,SATe;;AAWf;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EAnBF;IAoBI;IACA;IACA;IACA;;;AAGF;EACE;;AAEA;EACE;EACA;EACA;;AAEA;EALF;IAMI;;;AAIJ;EACE;EACA;EACA;;;AC3CN;EACE;EACA;EACA,QALkB;EAMlB,SAPmB;EAQnB;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;;;ACjBJ;ECkBE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EAGA,QAjCkB;EAkClB,WAnCqB;EAoCrB,aAlCuB;EAmCvB,SAtCmB;EAuCnB,eAnCyB;EAqCzB;EACA;;AAEA;EACE;;AAGF;EACE;;;AD3CJ;ECcE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EAGA,QAjCkB;EAkClB,WAnCqB;EAoCrB,aAlCuB;EAmCvB,SAtCmB;EAuCnB,eAnCyB;EAqCzB;EACA;EAgBA;;AAdA;EACE;;AAGF;EACE;;;ADvCJ;EACE;EACA;EACA,OCCqB;EDArB;EACA;EACA,aCFqB;EDGrB,eCF8B;;ADI9B;EACE,aCJ0B;;;ADQ9B;EACE;EACA,SCf2B;EDgB3B,aCjB+B;;;ADoBjC;EACE;EACA,YC3B4B;;;AD+B5B;EACE;;;AEnCJ;AAAA;ECOI;EACA;EACA,sBAXsB;EAYtB;EACA;EACA;EACA;EACA,eAZsB;EAatB;EACA;EACA;EACA,cAfqB;EAgBrB,QAlBoB;EAmBpB,SArBgB;EAsBhB;EACA;EACA,QAvBe;;AAyBf;AAAA;EACI,WAtB0B;EAuB1B;;;ADrBR;AAAA;ECCI;EACA;EACA,sBAXsB;EAYtB;EACA;EACA;EACA;EACA,eAZsB;EAatB;EACA;EACA;EACA,cAfqB;EAgBrB,QAlBoB;EAmBpB,SArBgB;EAsBhB;EACA;EACA,QAvBe;;AAyBf;AAAA;EACI,WAtB0B;EAuB1B;;;ADhBR;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AEvBJ;ECGI;EACA,WANkB;EAOlB;EACA,QAPe;EAQf,aAPoB;;ADGtB;EACE;;;AEEJ;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;;AChBJ;EDqBE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA,QA9Ba;EA+Bb;EACA,SA7BsB;EA8BtB;EACA;EACA;EACA;EACA;EACA,WAzCkB;EA0ClB;;AAEA;EAEE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA,OArDW;EAsDX,QAtDW;EAuDX;EACA;;AAGF;EACE;EACA;EACA,OA7DmB;EA8DnB,QA9DmB;EA+DnB;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAOA;EACE;EACA;;AAGF;EACE;;AAKN;AAAA;AAAA;EAGE;;;AE7GJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;;ACTJ;ECOI;EACA,QAVa;EAWb;EACA;EACA;EACA;EACA,SAdc;EAed,eAboB;EAcpB;EACA;;AAEA;EACI;EACA;;AAGJ;EACI,aAxB4B;EAyB5B;EACA;EACA;;AAIA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AChEZ;EACI;EACA;EACA;;AACA;EACI;EACA;;;AAIR;EACI;;;ACXJ;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;;ACHR;EACE,WAPwB;EAQxB;EACA;EACA,eAN4B;EAO5B;;AAEA;EAPF;IAQI,YAXuB;;;;AAe3B;EACE;EACA;EACA,QAnBqB;EAoBrB,SArBsB;EAsBtB;EACA;;AAGE;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;EACA;;AAIA;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;;AAIA;EACE;;AAGF;EACE;;AAIJ;EACE;;AAEA;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;EACA;EACA;EACA;;AAMR;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;;AAKN;EACE;;;AC7HF;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIJ;EACE;;AAGF;EACE;;AAEA;EACE;EACA;;;AC/DR;EACI,QAHc;EAId,OAJc;EAKd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;;;ACrBJ;ECCE;EACA;EACA;EACA,WANuB;EAOvB;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA,WA5BqB;EA6BrB;;AAEA;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACtDN;ECCE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;;ACfA;EACI;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAIR;EACI;EACA;;;ACpCR;EACI;EACA;;ACFJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AC7DJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;ACzEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AC9GJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;ACtBJ;EACE;EACA;;;ACFF;ECDE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;APtCR;EACI;EACA;;ACFJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AC7DJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;ACzEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AC9GJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AZlBJ;EACE,WAPwB;EAQxB;EACA;EACA,eAN4B;EAO5B;;AAEA;EAPF;IAQI,YAXuB;;;;AAe3B;EACE;EACA;EACA,QAnBqB;EAoBrB,SArBsB;EAsBtB;EACA;;AAGE;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;EACA;;AAIA;EACE;;AAGF;EACE;;AAIJ;EACE;EACA;EACA;;AAIA;EACE;;AAGF;EACE;;AAIJ;EACE;;AAEA;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;EACA;EACA;EACA;;AAMR;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;;AAKN;EACE;;;AgB9HE;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;;;A9BdR;EACE;EACA;EACA,QALkB;EAMlB,SAPmB;EAQnB;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;;;A+BnBJ;EACI;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;;AAIN;EACI;EACA;;;ACqIA;EANE;EACA,aAlEY;EAGd;EAsEE;;;AAGF;EAXE;EACA,aAlEY;EAGd;EA2EE;;;AAGF;EAhBE;EACA,aAlEY;EAGd;EAgFE;;;AAGF;EArBE;EACA,aAlEY;EAGd;EAqFE;;;AAGF;EA1BE;EACA,aAlEY;EAGd;;;AA4FA;EA9BE;EACA,aAlEY;EAGd;;AA+FE;EACE;;;AAIJ;EAtCE;EACA,aAlEY;EAGd;;;AAwGA;EA1CE;EACA,aAlEY;EAGd;;;AA4GA;EA9CE;EACA,aAlEY;EAGd;;;AAgHA;EAlDE;EACA,aAlEY;EAGd;;;AAoHA;EAtDE;EACA,aAlEY;EAGd;EAsHI;;;AAGJ;EA3DE;EACA,aAlEY;EAGd;EA2HE;;;AAGF;EAhEE;EACA,aAlEY;EAGd;EAgIE;;;AAGF;EArEE;EACA,aAlEY;EAGd;EAqIE;;;AAGF;EA1EE;EACA,aAlEY;EAGd;EA0IE;;;ACvNF;EACE;EACA;;;AAKA;EACE;;;ACTJ;EACI;EACA;;;ACAN;AAAA;AAAA;EAGE;EACA;;AA0HF;AAAA;AAAA;EACE,OAPM;;AASR;AAAA;AAAA;EACE,OAVM;;AAYR;AAAA;AAAA;EACE,OAbM;;AAoBN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;;;AApIJ;AAAA;EAEE;;;AAGF;EACE;;;AAGF;AAAA;EC2GA;EDxGE;;;AAGF;EACE;;;AAqGF;EACE,OAPM;;AASR;EACE,OAVM;;AAYR;EACE,OAbM;;AAoBN;EACE;;AA/GF;EACE;;AAGF;EACE;;AAGF;EACE;;;AAIJ;EACE;EACA;;AAiFF;EACE,OAPM;;AASR;EACE,OAVM;;AAYR;EACE,OAbM;;AAoBN;EACE;;AAMJ;EACE;;AAEF;EACE;;AAEF;EACE;;AAOA;EACE;;AAhHF;EACE;;;AAIJ;AAAA;ECsEA;;;ADjEA;ECiEA;;AD9DE;EC8DF;;ADtDE;ECsDF;;;AC9HA;AAAA;AAAA;EAGE;;;AAGF;AAAA;AAAA;EAGE;EACA;;AAEA;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;EACE;;AAGF;AAAA;AAAA;EACE;;AAIF;AAAA;AAAA;EACE;;;AAIJ;AAAA;AAAA;EAGE;;;AChCI;EACI;;AAGJ;EACI;;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIA;EACI;;AAIA;EACI;;AAGJ;EACI;;AAIR;EACI;;;ACtCd;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAKA;EACE;EACA;;AAGF;EACE;EACA;EACA;;;AAMF;EACE;EACA;;AAGF;EACE;;;AC7BF;EACE;;;ACFJ;EACE;EACA;EACA;;AAEA;EALF;IAMI;IACA;;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;;ACpBJ;EACE;;AAEA;EAEE;;;ACJF;EACE;;;ACAE;EACI;;AAGJ;EACI;;AAGJ;EACI;;;ACTJ;EACI;;;AAKJ;EACI;;;ACTV;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;;ACnBR;EACE,kBAPM;;AASR;EACE,kBAVM;;AAYR;EACE,kBAbM;;AAoBN;EAME,kBALY;;;AChCd;EACI;;;ACCJ;AAAA;EACE;;AAIA;AAAA;EACE;;AAGF;AAAA;EACE;;;ACbN;EACE;EACA;;AAEA;Ed2HF;;AcvHE;EduHF;;AcnHE;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;;AAKF;EACE;;;AC7BJ;EACE;EACA;;;ACAQ;EACE;EACA;;AAKN;EACE;;AAGF;EACE;EACA;EACA","file":"zitadel.css"} \ No newline at end of file diff --git a/internal/api/ui/login/static/templates/change_password.html b/internal/api/ui/login/static/templates/change_password.html index 456b9d444..45eacb3ab 100644 --- a/internal/api/ui/login/static/templates/change_password.html +++ b/internal/api/ui/login/static/templates/change_password.html @@ -12,7 +12,7 @@ {{ .CSRF }} - +
diff --git a/internal/api/ui/login/static/templates/external_not_found_option.html b/internal/api/ui/login/static/templates/external_not_found_option.html index 2edd1cc95..086662a8e 100644 --- a/internal/api/ui/login/static/templates/external_not_found_option.html +++ b/internal/api/ui/login/static/templates/external_not_found_option.html @@ -78,6 +78,10 @@ + +
diff --git a/internal/api/ui/login/static/templates/init_user.html b/internal/api/ui/login/static/templates/init_user.html index 1cc1073c8..cf0ad7104 100644 --- a/internal/api/ui/login/static/templates/init_user.html +++ b/internal/api/ui/login/static/templates/init_user.html @@ -16,7 +16,7 @@ - +
diff --git a/internal/api/ui/login/static/templates/password.html b/internal/api/ui/login/static/templates/password.html index f689188bb..15e9d7c09 100644 --- a/internal/api/ui/login/static/templates/password.html +++ b/internal/api/ui/login/static/templates/password.html @@ -12,7 +12,7 @@ {{ .CSRF }} - +
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 4de5b0237..09c64ba27 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -719,6 +719,7 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain func (repo *AuthRequestRepo) checkDomainDiscovery(ctx context.Context, request *domain.AuthRequest, loginName string) bool { // check if there's a suffix in the loginname + loginName = strings.TrimSpace(strings.ToLower(loginName)) index := strings.LastIndex(loginName, "@") if index < 0 { return false @@ -841,6 +842,7 @@ func queryLoginPolicyToDomain(policy *query.LoginPolicy) *domain.LoginPolicy { AllowRegister: policy.AllowRegister, AllowExternalIDP: policy.AllowExternalIDPs, ForceMFA: policy.ForceMFA, + ForceMFALocalOnly: policy.ForceMFALocalOnly, SecondFactors: policy.SecondFactors, MultiFactors: policy.MultiFactors, PasswordlessType: policy.PasswordlessType, @@ -974,7 +976,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth } } - step, ok, err := repo.mfaChecked(userSession, request, user) + step, ok, err := repo.mfaChecked(userSession, request, user, isInternalLogin && len(request.LinkingUsers) == 0) if err != nil { return nil, err } @@ -1093,9 +1095,9 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use return &domain.PasswordStep{} } -func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *domain.AuthRequest, user *user_model.UserView) (domain.NextStep, bool, error) { +func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *domain.AuthRequest, user *user_model.UserView, isInternalAuthentication bool) (domain.NextStep, bool, error) { mfaLevel := request.MFALevel() - allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy) + allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy, isInternalAuthentication) promptRequired := (user.MFAMaxSetUp < mfaLevel) || (len(allowedProviders) == 0 && required) if promptRequired || !repo.mfaSkippedOrSetUp(user, request) { types := user.MFATypesSetupPossible(mfaLevel, request.LoginPolicy) diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index c5dd8f411..bdcc01213 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -1439,6 +1439,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { userSession *user_model.UserSessionView request *domain.AuthRequest user *user_model.UserView + isInternal bool } tests := []struct { name string @@ -1472,6 +1473,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { MFAMaxSetUp: domain.MFALevelNotSetUp, }, }, + isInternal: true, }, nil, false, @@ -1490,6 +1492,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { MFAMaxSetUp: domain.MFALevelNotSetUp, }, }, + isInternal: true, }, nil, true, @@ -1509,6 +1512,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { MFAMaxSetUp: domain.MFALevelNotSetUp, }, }, + isInternal: true, }, &domain.MFAPromptStep{ MFAProviders: []domain.MFAType{ @@ -1533,6 +1537,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { MFAMaxSetUp: domain.MFALevelNotSetUp, }, }, + isInternal: true, }, &domain.MFAPromptStep{ Required: true, @@ -1557,6 +1562,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { MFAInitSkipped: testNow, }, }, + isInternal: true, }, nil, true, @@ -1578,6 +1584,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { }, }, userSession: &user_model.UserSessionView{SecondFactorVerification: testNow.Add(-5 * time.Hour)}, + isInternal: true, }, nil, true, @@ -1599,6 +1606,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { }, }, userSession: &user_model.UserSessionView{}, + isInternal: true, }, &domain.MFAVerificationStep{ @@ -1607,11 +1615,107 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { false, nil, }, + { + "external not checked or forced but set up, want step", + args{ + request: &domain.AuthRequest{ + LoginPolicy: &domain.LoginPolicy{ + SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, + SecondFactorCheckLifetime: 18 * time.Hour, + }, + }, + user: &user_model.UserView{ + HumanView: &user_model.HumanView{ + MFAMaxSetUp: domain.MFALevelSecondFactor, + OTPState: user_model.MFAStateReady, + }, + }, + userSession: &user_model.UserSessionView{}, + isInternal: false, + }, + &domain.MFAVerificationStep{ + MFAProviders: []domain.MFAType{domain.MFATypeOTP}, + }, + false, + nil, + }, + { + "external not forced but checked", + args{ + request: &domain.AuthRequest{ + LoginPolicy: &domain.LoginPolicy{ + SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, + SecondFactorCheckLifetime: 18 * time.Hour, + }, + }, + user: &user_model.UserView{ + HumanView: &user_model.HumanView{ + MFAMaxSetUp: domain.MFALevelSecondFactor, + OTPState: user_model.MFAStateReady, + }, + }, + userSession: &user_model.UserSessionView{SecondFactorVerification: testNow.Add(-5 * time.Hour)}, + isInternal: false, + }, + nil, + true, + nil, + }, + { + "external not checked but required, want step", + args{ + request: &domain.AuthRequest{ + LoginPolicy: &domain.LoginPolicy{ + SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, + SecondFactorCheckLifetime: 18 * time.Hour, + ForceMFA: true, + }, + }, + user: &user_model.UserView{ + HumanView: &user_model.HumanView{ + MFAMaxSetUp: domain.MFALevelNotSetUp, + }, + }, + userSession: &user_model.UserSessionView{}, + isInternal: false, + }, + &domain.MFAPromptStep{ + Required: true, + MFAProviders: []domain.MFAType{ + domain.MFATypeOTP, + }, + }, + false, + nil, + }, + { + "external not checked but local required", + args{ + request: &domain.AuthRequest{ + LoginPolicy: &domain.LoginPolicy{ + SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, + SecondFactorCheckLifetime: 18 * time.Hour, + ForceMFA: true, + ForceMFALocalOnly: true, + }, + }, + user: &user_model.UserView{ + HumanView: &user_model.HumanView{ + MFAMaxSetUp: domain.MFALevelNotSetUp, + }, + }, + userSession: &user_model.UserSessionView{}, + isInternal: false, + }, + nil, + true, + nil, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { repo := &AuthRequestRepo{} - got, ok, err := repo.mfaChecked(tt.args.userSession, tt.args.request, tt.args.user) + got, ok, err := repo.mfaChecked(tt.args.userSession, tt.args.request, tt.args.user, tt.args.isInternal) if (tt.errFunc != nil && !tt.errFunc(err)) || (err != nil && tt.errFunc == nil) { t.Errorf("got wrong err: %v ", err) return diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index b2bff6155..3fc61c854 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -15,7 +15,9 @@ import ( "github.com/zitadel/zitadel/internal/api/authz" http_util "github.com/zitadel/zitadel/internal/api/http" "github.com/zitadel/zitadel/internal/authz/repository/eventsourcing/view" + "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" v1 "github.com/zitadel/zitadel/internal/eventstore/v1" "github.com/zitadel/zitadel/internal/eventstore/v1/models" @@ -28,7 +30,6 @@ import ( type TokenVerifierRepo struct { TokenVerificationKey crypto.EncryptionAlgorithm - IAMID string Eventstore v1.Eventstore View *view.View Query *query.Queries @@ -92,6 +93,21 @@ func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenStrin if !ok { return "", "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Reb32", "invalid token") } + if strings.HasPrefix(tokenID, command.IDPrefixV2) { + userID, clientID, resourceOwner, err = repo.verifyAccessTokenV2(ctx, tokenID, verifierClientID, projectID) + return + } + if sessionID, ok := strings.CutPrefix(tokenID, authz.SessionTokenPrefix); ok { + userID, clientID, resourceOwner, err = repo.verifySessionToken(ctx, sessionID, tokenString) + return + } + return repo.verifyAccessTokenV1(ctx, tokenID, subject, verifierClientID, projectID) +} + +func (repo *TokenVerifierRepo) verifyAccessTokenV1(ctx context.Context, tokenID, subject, verifierClientID, projectID string) (userID string, agentID string, clientID, prefLang, resourceOwner string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + _, tokenSpan := tracing.NewNamedSpan(ctx, "token") token, err := repo.tokenByID(ctx, tokenID, subject) tokenSpan.EndWithError(err) @@ -104,12 +120,98 @@ func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenStrin if token.IsPAT { return token.UserID, "", "", "", token.ResourceOwner, nil } - for _, aud := range token.Audience { - if verifierClientID == aud || projectID == aud { - return token.UserID, token.UserAgentID, token.ApplicationID, token.PreferredLanguage, token.ResourceOwner, nil + if err = verifyAudience(token.Audience, verifierClientID, projectID); err != nil { + return "", "", "", "", "", err + } + return token.UserID, token.UserAgentID, token.ApplicationID, token.PreferredLanguage, token.ResourceOwner, nil +} + +func (repo *TokenVerifierRepo) verifyAccessTokenV2(ctx context.Context, token, verifierClientID, projectID string) (userID, clientID, resourceOwner string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + activeToken, err := repo.Query.ActiveAccessTokenByToken(ctx, token) + if err != nil { + return "", "", "", err + } + if err = verifyAudience(activeToken.Audience, verifierClientID, projectID); err != nil { + return "", "", "", err + } + if err = repo.checkAuthentication(ctx, activeToken.AuthMethods, activeToken.UserID); err != nil { + return "", "", "", err + } + return activeToken.UserID, activeToken.ClientID, activeToken.ResourceOwner, nil +} + +func (repo *TokenVerifierRepo) verifySessionToken(ctx context.Context, sessionID, token string) (userID, clientID, resourceOwner string, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + session, err := repo.Query.SessionByID(ctx, false, sessionID, token) + if err != nil { + return "", "", "", err + } + if err = repo.checkAuthentication(ctx, authMethodsFromSession(session), session.UserFactor.UserID); err != nil { + return "", "", "", err + } + return session.UserFactor.UserID, "", session.UserFactor.ResourceOwner, nil +} + +// checkAuthentication ensures the session or token was authenticated (at least a single [domain.UserAuthMethodType]). +// It will also check if there was a multi factor authentication, if either MFA is forced by the login policy or if the user has set up any +func (repo *TokenVerifierRepo) checkAuthentication(ctx context.Context, authMethods []domain.UserAuthMethodType, userID string) error { + if len(authMethods) == 0 { + return caos_errs.ThrowPermissionDenied(nil, "AUTHZ-Kl3p0", "authentication required") + } + if domain.HasMFA(authMethods) { + return nil + } + availableAuthMethods, forceMFA, forceMFALocalOnly, err := repo.Query.ListUserAuthMethodTypesRequired(setCallerCtx(ctx, userID), userID, false) + if err != nil { + return err + } + if domain.RequiresMFA(forceMFA, forceMFALocalOnly, hasIDPAuthentication(authMethods)) || domain.HasMFA(availableAuthMethods) { + return caos_errs.ThrowPermissionDenied(nil, "AUTHZ-Kl3p0", "mfa required") + } + return nil +} + +func hasIDPAuthentication(authMethods []domain.UserAuthMethodType) bool { + for _, method := range authMethods { + if method == domain.UserAuthMethodTypeIDP { + return true } } - return "", "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience") + return false +} + +func authMethodsFromSession(session *query.Session) []domain.UserAuthMethodType { + types := make([]domain.UserAuthMethodType, 0, domain.UserAuthMethodTypeIDP) + if !session.PasswordFactor.PasswordCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypePassword) + } + if !session.PasskeyFactor.PasskeyCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypePasswordless) + } + if !session.IntentFactor.IntentCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeIDP) + } + // TODO: add checks with https://github.com/zitadel/zitadel/issues/5477 + /* + if !session.TOTPFactor.TOTPCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeOTP) + } + if !session.U2FFactor.U2FCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeU2F) + } + */ + return types +} + +func setCallerCtx(ctx context.Context, userID string) context.Context { + ctxData := authz.GetCtxData(ctx) + ctxData.UserID = userID + return authz.SetCtxData(ctx, ctxData) } func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) { @@ -184,6 +286,15 @@ func (repo *TokenVerifierRepo) decryptAccessToken(token string) (string, error) return tokenIDSubject, nil } +func verifyAudience(audience []string, verifierClientID, projectID string) error { + for _, aud := range audience { + if verifierClientID == aud || projectID == aud { + return nil + } + } + return caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience") +} + type openIDKeySet struct { *query.Queries } diff --git a/internal/command/auth_request.go b/internal/command/auth_request.go new file mode 100644 index 000000000..bbcee503c --- /dev/null +++ b/internal/command/auth_request.go @@ -0,0 +1,214 @@ +package command + +import ( + "context" + "time" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/repository/authrequest" + "github.com/zitadel/zitadel/internal/telemetry/tracing" +) + +type AuthRequest struct { + ID string + LoginClient string + ClientID string + RedirectURI string + State string + Nonce string + Scope []string + Audience []string + ResponseType domain.OIDCResponseType + CodeChallenge *domain.OIDCCodeChallenge + Prompt []domain.Prompt + UILocales []string + MaxAge *time.Duration + LoginHint *string + HintUserID *string +} + +type CurrentAuthRequest struct { + *AuthRequest + SessionID string + UserID string + AuthMethods []domain.UserAuthMethodType + AuthTime time.Time +} + +const IDPrefixV2 = "V2_" + +func (c *Commands) AddAuthRequest(ctx context.Context, authRequest *AuthRequest) (_ *CurrentAuthRequest, err error) { + authRequestID, err := c.idGenerator.Next() + if err != nil { + return nil, err + } + authRequest.ID = IDPrefixV2 + authRequestID + writeModel, err := c.getAuthRequestWriteModel(ctx, authRequest.ID) + if err != nil { + return nil, err + } + if writeModel.AuthRequestState != domain.AuthRequestStateUnspecified { + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-Sf3gt", "Errors.AuthRequest.AlreadyExisting") + } + err = c.pushAppendAndReduce(ctx, writeModel, authrequest.NewAddedEvent( + ctx, + &authrequest.NewAggregate(authRequest.ID, authz.GetInstance(ctx).InstanceID()).Aggregate, + authRequest.LoginClient, + authRequest.ClientID, + authRequest.RedirectURI, + authRequest.State, + authRequest.Nonce, + authRequest.Scope, + authRequest.Audience, + authRequest.ResponseType, + authRequest.CodeChallenge, + authRequest.Prompt, + authRequest.UILocales, + authRequest.MaxAge, + authRequest.LoginHint, + authRequest.HintUserID, + )) + if err != nil { + return nil, err + } + return authRequestWriteModelToCurrentAuthRequest(writeModel), nil +} + +func (c *Commands) LinkSessionToAuthRequest(ctx context.Context, id, sessionID, sessionToken string, checkLoginClient bool) (*domain.ObjectDetails, *CurrentAuthRequest, error) { + writeModel, err := c.getAuthRequestWriteModel(ctx, id) + if err != nil { + return nil, nil, err + } + if writeModel.AuthRequestState == domain.AuthRequestStateUnspecified { + return nil, nil, errors.ThrowNotFound(nil, "COMMAND-jae5P", "Errors.AuthRequest.NotExisting") + } + if writeModel.AuthRequestState != domain.AuthRequestStateAdded { + return nil, nil, errors.ThrowPreconditionFailed(nil, "COMMAND-Sx208nt", "Errors.AuthRequest.AlreadyHandled") + } + if checkLoginClient && authz.GetCtxData(ctx).UserID != writeModel.LoginClient { + return nil, nil, errors.ThrowPermissionDenied(nil, "COMMAND-rai9Y", "Errors.AuthRequest.WrongLoginClient") + } + sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetCtxData(ctx).OrgID) + err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel) + if err != nil { + return nil, nil, err + } + if sessionWriteModel.State == domain.SessionStateUnspecified { + return nil, nil, errors.ThrowNotFound(nil, "COMMAND-x0099887", "Errors.Session.NotExisting") + } + if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionWrite); err != nil { + return nil, nil, err + } + + if err := c.pushAppendAndReduce(ctx, writeModel, authrequest.NewSessionLinkedEvent( + ctx, &authrequest.NewAggregate(id, authz.GetInstance(ctx).InstanceID()).Aggregate, + sessionID, + sessionWriteModel.UserID, + sessionWriteModel.AuthenticationTime(), + sessionWriteModel.AuthMethodTypes(), + )); err != nil { + return nil, nil, err + } + return writeModelToObjectDetails(&writeModel.WriteModel), authRequestWriteModelToCurrentAuthRequest(writeModel), nil +} + +func (c *Commands) FailAuthRequest(ctx context.Context, id string, reason domain.OIDCErrorReason) (*domain.ObjectDetails, *CurrentAuthRequest, error) { + writeModel, err := c.getAuthRequestWriteModel(ctx, id) + if err != nil { + return nil, nil, err + } + if writeModel.AuthRequestState != domain.AuthRequestStateAdded { + return nil, nil, errors.ThrowPreconditionFailed(nil, "COMMAND-Sx202nt", "Errors.AuthRequest.AlreadyHandled") + } + err = c.pushAppendAndReduce(ctx, writeModel, authrequest.NewFailedEvent( + ctx, + &authrequest.NewAggregate(id, authz.GetInstance(ctx).InstanceID()).Aggregate, + reason, + )) + if err != nil { + return nil, nil, err + } + return writeModelToObjectDetails(&writeModel.WriteModel), authRequestWriteModelToCurrentAuthRequest(writeModel), nil +} + +func (c *Commands) AddAuthRequestCode(ctx context.Context, authRequestID, code string) (err error) { + if code == "" { + return errors.ThrowPreconditionFailed(nil, "COMMAND-Ht52d", "Errors.AuthRequest.InvalidCode") + } + writeModel, err := c.getAuthRequestWriteModel(ctx, authRequestID) + if err != nil { + return err + } + if writeModel.AuthRequestState != domain.AuthRequestStateAdded || writeModel.SessionID == "" { + return errors.ThrowPreconditionFailed(nil, "COMMAND-SFwd2", "Errors.AuthRequest.AlreadyHandled") + } + return c.pushAppendAndReduce(ctx, writeModel, authrequest.NewCodeAddedEvent(ctx, + &authrequest.NewAggregate(writeModel.AggregateID, authz.GetInstance(ctx).InstanceID()).Aggregate)) +} + +func (c *Commands) ExchangeAuthCode(ctx context.Context, code string) (authRequest *CurrentAuthRequest, err error) { + if code == "" { + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-Sf3g2", "Errors.AuthRequest.InvalidCode") + } + writeModel, err := c.getAuthRequestWriteModel(ctx, code) + if err != nil { + return nil, err + } + if writeModel.AuthRequestState != domain.AuthRequestStateCodeAdded { + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-SFwd2", "Errors.AuthRequest.NoCode") + } + err = c.pushAppendAndReduce(ctx, writeModel, authrequest.NewCodeExchangedEvent(ctx, + &authrequest.NewAggregate(writeModel.AggregateID, authz.GetInstance(ctx).InstanceID()).Aggregate)) + if err != nil { + return nil, err + } + return authRequestWriteModelToCurrentAuthRequest(writeModel), nil +} + +func authRequestWriteModelToCurrentAuthRequest(writeModel *AuthRequestWriteModel) (_ *CurrentAuthRequest) { + return &CurrentAuthRequest{ + AuthRequest: &AuthRequest{ + ID: writeModel.AggregateID, + LoginClient: writeModel.LoginClient, + ClientID: writeModel.ClientID, + RedirectURI: writeModel.RedirectURI, + State: writeModel.State, + Nonce: writeModel.Nonce, + Scope: writeModel.Scope, + Audience: writeModel.Audience, + ResponseType: writeModel.ResponseType, + CodeChallenge: writeModel.CodeChallenge, + Prompt: writeModel.Prompt, + UILocales: writeModel.UILocales, + MaxAge: writeModel.MaxAge, + LoginHint: writeModel.LoginHint, + HintUserID: writeModel.HintUserID, + }, + SessionID: writeModel.SessionID, + UserID: writeModel.UserID, + AuthMethods: writeModel.AuthMethods, + AuthTime: writeModel.AuthTime, + } +} + +func (c *Commands) GetCurrentAuthRequest(ctx context.Context, id string) (_ *CurrentAuthRequest, err error) { + wm, err := c.getAuthRequestWriteModel(ctx, id) + if err != nil { + return nil, err + } + return authRequestWriteModelToCurrentAuthRequest(wm), nil +} + +func (c *Commands) getAuthRequestWriteModel(ctx context.Context, id string) (writeModel *AuthRequestWriteModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + writeModel = NewAuthRequestWriteModel(ctx, id) + err = c.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, err + } + return writeModel, nil +} diff --git a/internal/command/auth_request_model.go b/internal/command/auth_request_model.go new file mode 100644 index 000000000..d27caf876 --- /dev/null +++ b/internal/command/auth_request_model.go @@ -0,0 +1,110 @@ +package command + +import ( + "context" + "time" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/authrequest" +) + +type AuthRequestWriteModel struct { + eventstore.WriteModel + aggregate *eventstore.Aggregate + + LoginClient string + ClientID string + RedirectURI string + State string + Nonce string + Scope []string + Audience []string + ResponseType domain.OIDCResponseType + CodeChallenge *domain.OIDCCodeChallenge + Prompt []domain.Prompt + UILocales []string + MaxAge *time.Duration + LoginHint *string + HintUserID *string + SessionID string + UserID string + AuthTime time.Time + AuthMethods []domain.UserAuthMethodType + AuthRequestState domain.AuthRequestState +} + +func NewAuthRequestWriteModel(ctx context.Context, id string) *AuthRequestWriteModel { + return &AuthRequestWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: id, + }, + aggregate: &authrequest.NewAggregate(id, authz.GetInstance(ctx).InstanceID()).Aggregate, + } +} + +func (m *AuthRequestWriteModel) Reduce() error { + for _, event := range m.Events { + switch e := event.(type) { + case *authrequest.AddedEvent: + m.LoginClient = e.LoginClient + m.ClientID = e.ClientID + m.RedirectURI = e.RedirectURI + m.State = e.State + m.Nonce = e.Nonce + m.Scope = e.Scope + m.Audience = e.Audience + m.ResponseType = e.ResponseType + m.CodeChallenge = e.CodeChallenge + m.Prompt = e.Prompt + m.UILocales = e.UILocales + m.MaxAge = e.MaxAge + m.LoginHint = e.LoginHint + m.HintUserID = e.HintUserID + m.AuthRequestState = domain.AuthRequestStateAdded + case *authrequest.SessionLinkedEvent: + m.SessionID = e.SessionID + m.UserID = e.UserID + m.AuthTime = e.AuthTime + m.AuthMethods = e.AuthMethods + case *authrequest.CodeAddedEvent: + m.AuthRequestState = domain.AuthRequestStateCodeAdded + case *authrequest.FailedEvent: + m.AuthRequestState = domain.AuthRequestStateFailed + case *authrequest.CodeExchangedEvent: + m.AuthRequestState = domain.AuthRequestStateCodeExchanged + case *authrequest.SucceededEvent: + m.AuthRequestState = domain.AuthRequestStateSucceeded + } + } + + return m.WriteModel.Reduce() +} + +func (m *AuthRequestWriteModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AddQuery(). + AggregateTypes(authrequest.AggregateType). + AggregateIDs(m.AggregateID). + Builder() +} + +// CheckAuthenticated checks that the auth request exists, a session must have been linked +// and in case of a Code Flow the code must have been exchanged +func (m *AuthRequestWriteModel) CheckAuthenticated() error { + if m.SessionID == "" { + return caos_errs.ThrowPreconditionFailed(nil, "AUTHR-SF2r2", "Errors.AuthRequest.NotAuthenticated") + } + // in case of OIDC Code Flow, the code must have been exchanged + if m.ResponseType == domain.OIDCResponseTypeCode && m.AuthRequestState == domain.AuthRequestStateCodeExchanged { + return nil + } + // in case of OIDC Implicit Flow, check that the requests exists, but has not succeeded yet + if (m.ResponseType == domain.OIDCResponseTypeIDToken || m.ResponseType == domain.OIDCResponseTypeIDTokenToken) && + m.AuthRequestState == domain.AuthRequestStateAdded { + return nil + } + return caos_errs.ThrowPreconditionFailed(nil, "AUTHR-sajk3", "Errors.AuthRequest.NotAuthenticated") +} diff --git a/internal/command/auth_request_test.go b/internal/command/auth_request_test.go new file mode 100644 index 000000000..f54043b36 --- /dev/null +++ b/internal/command/auth_request_test.go @@ -0,0 +1,997 @@ +package command + +import ( + "context" + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/id" + "github.com/zitadel/zitadel/internal/id/mock" + "github.com/zitadel/zitadel/internal/repository/authrequest" + "github.com/zitadel/zitadel/internal/repository/session" +) + +func TestCommands_AddAuthRequest(t *testing.T) { + mockCtx := authz.NewMockContext("instanceID", "orgID", "loginClient") + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + } + type args struct { + ctx context.Context + request *AuthRequest + } + tests := []struct { + name string + fields fields + args args + want *CurrentAuthRequest + wantErr error + }{ + { + "already exists error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + ), + idGenerator: mock.NewIDGeneratorExpectIDs(t, "id"), + }, + args{ + ctx: mockCtx, + request: &AuthRequest{}, + }, + nil, + caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sf3gt", "Errors.AuthRequest.AlreadyExisting"), + }, + { + "added", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + }), + ), + idGenerator: mock.NewIDGeneratorExpectIDs(t, "id"), + }, + args{ + ctx: mockCtx, + request: &AuthRequest{ + LoginClient: "loginClient", + ClientID: "clientID", + RedirectURI: "redirectURI", + State: "state", + Nonce: "nonce", + Scope: []string{"openid"}, + Audience: []string{"audience"}, + ResponseType: domain.OIDCResponseTypeCode, + CodeChallenge: &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + Prompt: []domain.Prompt{domain.PromptNone}, + UILocales: []string{"en", "de"}, + MaxAge: gu.Ptr(time.Duration(0)), + LoginHint: gu.Ptr("loginHint"), + HintUserID: gu.Ptr("hintUserID"), + }, + }, + &CurrentAuthRequest{ + AuthRequest: &AuthRequest{ + ID: "V2_id", + LoginClient: "loginClient", + ClientID: "clientID", + RedirectURI: "redirectURI", + State: "state", + Nonce: "nonce", + Scope: []string{"openid"}, + Audience: []string{"audience"}, + ResponseType: domain.OIDCResponseTypeCode, + CodeChallenge: &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + Prompt: []domain.Prompt{domain.PromptNone}, + UILocales: []string{"en", "de"}, + MaxAge: gu.Ptr(time.Duration(0)), + LoginHint: gu.Ptr("loginHint"), + HintUserID: gu.Ptr("hintUserID"), + }, + }, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + } + got, err := c.AddAuthRequest(tt.args.ctx, tt.args.request) + require.ErrorIs(t, tt.wantErr, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestCommands_LinkSessionToAuthRequest(t *testing.T) { + mockCtx := authz.NewMockContext("instanceID", "orgID", "loginClient") + type fields struct { + eventstore *eventstore.Eventstore + tokenVerifier func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) + checkPermission domain.PermissionCheck + } + type args struct { + ctx context.Context + id string + sessionID string + sessionToken string + checkLoginClient bool + } + type res struct { + details *domain.ObjectDetails + authReq *CurrentAuthRequest + wantErr error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "authRequest not found", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckNotAllowed(), + }, + args{ + ctx: mockCtx, + id: "id", + sessionID: "sessionID", + }, + res{ + wantErr: caos_errs.ThrowNotFound(nil, "COMMAND-jae5P", "Errors.AuthRequest.NotExisting"), + }, + }, + { + "authRequest not existing", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + eventFromEventPusher( + authrequest.NewFailedEvent(mockCtx, &authrequest.NewAggregate("id", "instanceID").Aggregate, + domain.OIDCErrorReasonUnspecified), + ), + ), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckAllowed(), + }, + args{ + ctx: mockCtx, + id: "id", + sessionID: "sessionID", + }, + res{ + wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sx208nt", "Errors.AuthRequest.AlreadyHandled"), + }, + }, + { + "wrong login client", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckAllowed(), + }, + args{ + ctx: authz.NewMockContext("instanceID", "orgID", "wrongLoginClient"), + id: "id", + sessionID: "sessionID", + sessionToken: "token", + checkLoginClient: true, + }, + res{ + wantErr: caos_errs.ThrowPermissionDenied(nil, "COMMAND-rai9Y", "Errors.AuthRequest.WrongLoginClient"), + }, + }, + { + "session not existing", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + expectFilter(), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckNotAllowed(), + }, + args{ + ctx: mockCtx, + id: "V2_id", + sessionID: "sessionID", + }, + res{ + wantErr: caos_errs.ThrowNotFound(nil, "COMMAND-x0099887", "Errors.Session.NotExisting"), + }, + }, + { + "missing permission", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + expectFilter( + eventFromEventPusher( + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + ), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckNotAllowed(), + }, + args{ + ctx: mockCtx, + id: "V2_id", + sessionID: "sessionID", + }, + res{ + wantErr: caos_errs.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"), + }, + }, + { + "invalid session token", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + expectFilter( + eventFromEventPusher( + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + ), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return caos_errs.ThrowPermissionDenied(nil, "COMMAND-sGr42", "Errors.Session.Token.Invalid") + }, + }, + args{ + ctx: mockCtx, + id: "V2_id", + sessionID: "sessionID", + sessionToken: "invalid", + }, + res{ + wantErr: caos_errs.ThrowPermissionDenied(nil, "COMMAND-sGr42", "Errors.Session.Token.Invalid"), + }, + }, + { + "linked", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + expectFilter( + eventFromEventPusher( + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), + ), + eventFromEventPusher( + session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, + "userID", testNow), + ), + eventFromEventPusher( + session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, + testNow), + ), + ), + expectPush( + []*repository.Event{eventFromEventPusherWithInstanceID( + "instanceID", + authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + )}), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckAllowed(), + }, + args{ + ctx: mockCtx, + id: "V2_id", + sessionID: "sessionID", + sessionToken: "token", + }, + res{ + details: &domain.ObjectDetails{ResourceOwner: "instanceID"}, + authReq: &CurrentAuthRequest{ + AuthRequest: &AuthRequest{ + ID: "V2_id", + LoginClient: "loginClient", + ClientID: "clientID", + RedirectURI: "redirectURI", + State: "state", + Nonce: "nonce", + Scope: []string{"openid"}, + Audience: []string{"audience"}, + ResponseType: domain.OIDCResponseTypeCode, + }, + SessionID: "sessionID", + UserID: "userID", + AuthMethods: []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + }, + }, + }, + { + "linked with login client check", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + expectFilter( + eventFromEventPusher( + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), + ), + eventFromEventPusher( + session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, + "userID", testNow), + ), + eventFromEventPusher( + session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, + testNow), + ), + ), + expectPush( + []*repository.Event{eventFromEventPusherWithInstanceID( + "instanceID", + authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + )}), + ), + tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { + return nil + }, + checkPermission: newMockPermissionCheckAllowed(), + }, + args{ + ctx: authz.NewMockContext("instanceID", "orgID", "loginClient"), + id: "V2_id", + sessionID: "sessionID", + sessionToken: "token", + checkLoginClient: true, + }, + res{ + details: &domain.ObjectDetails{ResourceOwner: "instanceID"}, + authReq: &CurrentAuthRequest{ + AuthRequest: &AuthRequest{ + ID: "V2_id", + LoginClient: "loginClient", + ClientID: "clientID", + RedirectURI: "redirectURI", + State: "state", + Nonce: "nonce", + Scope: []string{"openid"}, + Audience: []string{"audience"}, + ResponseType: domain.OIDCResponseTypeCode, + }, + SessionID: "sessionID", + UserID: "userID", + AuthMethods: []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + sessionTokenVerifier: tt.fields.tokenVerifier, + checkPermission: tt.fields.checkPermission, + } + details, got, err := c.LinkSessionToAuthRequest(tt.args.ctx, tt.args.id, tt.args.sessionID, tt.args.sessionToken, tt.args.checkLoginClient) + require.ErrorIs(t, err, tt.res.wantErr) + assert.Equal(t, tt.res.details, details) + if err == nil { + assert.WithinRange(t, got.AuthTime, testNow, testNow) + got.AuthTime = time.Time{} + } + assert.Equal(t, tt.res.authReq, got) + }) + } +} + +func TestCommands_FailAuthRequest(t *testing.T) { + mockCtx := authz.NewMockContext("instanceID", "orgID", "loginClient") + type fields struct { + eventstore *eventstore.Eventstore + } + type args struct { + ctx context.Context + id string + reason domain.OIDCErrorReason + } + type res struct { + details *domain.ObjectDetails + authReq *CurrentAuthRequest + wantErr error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "authRequest not existing", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + }, + args{ + ctx: mockCtx, + id: "foo", + reason: domain.OIDCErrorReasonLoginRequired, + }, + res{ + wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sx202nt", "Errors.AuthRequest.AlreadyHandled"), + }, + }, + { + "failed", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + nil, + nil, + nil, + nil, + nil, + nil, + ), + ), + ), + expectPush( + []*repository.Event{eventFromEventPusherWithInstanceID( + "instanceID", + authrequest.NewFailedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate, + domain.OIDCErrorReasonLoginRequired), + )}), + ), + }, + args{ + ctx: mockCtx, + id: "V2_id", + reason: domain.OIDCErrorReasonLoginRequired, + }, + res{ + details: &domain.ObjectDetails{ResourceOwner: "instanceID"}, + authReq: &CurrentAuthRequest{ + AuthRequest: &AuthRequest{ + ID: "V2_id", + LoginClient: "loginClient", + ClientID: "clientID", + RedirectURI: "redirectURI", + State: "state", + Nonce: "nonce", + Scope: []string{"openid"}, + Audience: []string{"audience"}, + ResponseType: domain.OIDCResponseTypeCode, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + } + details, got, err := c.FailAuthRequest(tt.args.ctx, tt.args.id, tt.args.reason) + require.ErrorIs(t, err, tt.res.wantErr) + assert.Equal(t, tt.res.details, details) + assert.Equal(t, tt.res.authReq, got) + }) + } +} + +func TestCommands_AddAuthRequestCode(t *testing.T) { + mockCtx := authz.NewMockContext("instanceID", "orgID", "loginClient") + type fields struct { + eventstore *eventstore.Eventstore + } + type args struct { + ctx context.Context + id string + code string + } + tests := []struct { + name string + fields fields + args args + wantErr error + }{ + { + "empty code error", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: mockCtx, + id: "V2_authRequestID", + code: "", + }, + caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Ht52d", "Errors.AuthRequest.InvalidCode"), + }, + { + "no session linked error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + ), + ), + }, + args{ + ctx: mockCtx, + id: "V2_authRequestID", + code: "V2_authRequestID", + }, + caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFwd2", "Errors.AuthRequest.AlreadyHandled"), + }, + { + "success", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + eventFromEventPusher( + authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + authrequest.NewCodeAddedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + }, + ), + ), + }, + args{ + ctx: mockCtx, + id: "V2_authRequestID", + code: "V2_authRequestID", + }, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + } + err := c.AddAuthRequestCode(tt.args.ctx, tt.args.id, tt.args.code) + assert.ErrorIs(t, tt.wantErr, err) + }) + } +} + +func TestCommands_ExchangeAuthCode(t *testing.T) { + mockCtx := authz.NewMockContext("instanceID", "orgID", "loginClient") + type fields struct { + eventstore *eventstore.Eventstore + } + type args struct { + ctx context.Context + code string + } + type res struct { + authRequest *CurrentAuthRequest + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "empty code error", + fields{ + eventstore: eventstoreExpect(t), + }, + args{ + ctx: mockCtx, + code: "", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sf3g2", "Errors.AuthRequest.InvalidCode"), + }, + }, + { + "no code added error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + ), + ), + }, + args{ + ctx: mockCtx, + code: "V2_authRequestID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFwd2", "Errors.AuthRequest.NoCode"), + }, + }, + { + "code exchanged", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + eventFromEventPusher( + authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + ), + eventFromEventPusher( + authrequest.NewCodeAddedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + authrequest.NewCodeExchangedEvent(mockCtx, &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + }, + ), + ), + }, + args{ + ctx: mockCtx, + code: "V2_authRequestID", + }, + res{ + authRequest: &CurrentAuthRequest{ + AuthRequest: &AuthRequest{ + ID: "V2_authRequestID", + LoginClient: "loginClient", + ClientID: "clientID", + RedirectURI: "redirectURI", + State: "state", + Nonce: "nonce", + Scope: []string{"openid"}, + Audience: []string{"audience"}, + ResponseType: domain.OIDCResponseTypeCode, + CodeChallenge: &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + Prompt: []domain.Prompt{domain.PromptNone}, + UILocales: []string{"en", "de"}, + MaxAge: gu.Ptr(time.Duration(0)), + LoginHint: gu.Ptr("loginHint"), + HintUserID: gu.Ptr("hintUserID"), + }, + SessionID: "sessionID", + UserID: "userID", + AuthMethods: []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + } + got, err := c.ExchangeAuthCode(tt.args.ctx, tt.args.code) + assert.ErrorIs(t, tt.res.err, err) + + if err == nil { + // equal on time won't work -> test separately and clear it before comparing the rest + assert.WithinRange(t, got.AuthTime, testNow, testNow) + got.AuthTime = time.Time{} + } + assert.Equal(t, tt.res.authRequest, got) + }) + } +} diff --git a/internal/command/command.go b/internal/command/command.go index 3c804576b..9a6a87cb7 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -15,9 +15,12 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/repository/action" + "github.com/zitadel/zitadel/internal/repository/authrequest" "github.com/zitadel/zitadel/internal/repository/idpintent" instance_repo "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/keypair" + "github.com/zitadel/zitadel/internal/repository/milestone" + "github.com/zitadel/zitadel/internal/repository/oidcsession" "github.com/zitadel/zitadel/internal/repository/org" proj_repo "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/quota" @@ -42,18 +45,22 @@ type Commands struct { externalSecure bool externalPort uint16 - idpConfigEncryption crypto.EncryptionAlgorithm - smtpEncryption crypto.EncryptionAlgorithm - smsEncryption crypto.EncryptionAlgorithm - userEncryption crypto.EncryptionAlgorithm - userPasswordAlg crypto.HashAlgorithm - machineKeySize int - applicationKeySize int - domainVerificationAlg crypto.EncryptionAlgorithm - domainVerificationGenerator crypto.Generator - domainVerificationValidator func(domain, token, verifier string, checkType api_http.CheckType) error - sessionTokenCreator func(sessionID string) (id string, token string, err error) - sessionTokenVerifier func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) + idpConfigEncryption crypto.EncryptionAlgorithm + smtpEncryption crypto.EncryptionAlgorithm + smsEncryption crypto.EncryptionAlgorithm + userEncryption crypto.EncryptionAlgorithm + userPasswordHasher *crypto.PasswordHasher + codeAlg crypto.HashAlgorithm + machineKeySize int + applicationKeySize int + domainVerificationAlg crypto.EncryptionAlgorithm + domainVerificationGenerator crypto.Generator + domainVerificationValidator func(domain, token, verifier string, checkType api_http.CheckType) error + sessionTokenCreator func(sessionID string) (id string, token string, err error) + sessionTokenVerifier func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) + defaultAccessTokenLifetime time.Duration + defaultRefreshTokenLifetime time.Duration + defaultRefreshTokenIdleLifetime time.Duration multifactors domain.MultifactorConfigs webauthnConfig *webauthn_helper.Config @@ -79,6 +86,9 @@ func StartCommands( httpClient *http.Client, permissionCheck domain.PermissionCheck, sessionTokenVerifier func(ctx context.Context, sessionToken string, sessionID string, tokenID string) (err error), + defaultAccessTokenLifetime, + defaultRefreshTokenLifetime, + defaultRefreshTokenIdleLifetime time.Duration, ) (repo *Commands, err error) { if externalDomain == "" { return nil, errors.ThrowInvalidArgument(nil, "COMMAND-Df21s", "no external domain specified") @@ -87,31 +97,34 @@ func StartCommands( // reuse the oidcEncryption to be able to handle both tokens in the interceptor later on sessionAlg := oidcEncryption repo = &Commands{ - eventstore: es, - static: staticStore, - idGenerator: idGenerator, - zitadelRoles: zitadelRoles, - externalDomain: externalDomain, - externalSecure: externalSecure, - externalPort: externalPort, - keySize: defaults.KeyConfig.Size, - certKeySize: defaults.KeyConfig.CertificateSize, - privateKeyLifetime: defaults.KeyConfig.PrivateKeyLifetime, - publicKeyLifetime: defaults.KeyConfig.PublicKeyLifetime, - certificateLifetime: defaults.KeyConfig.CertificateLifetime, - idpConfigEncryption: idpConfigEncryption, - smtpEncryption: smtpEncryption, - smsEncryption: smsEncryption, - userEncryption: userEncryption, - domainVerificationAlg: domainVerificationEncryption, - keyAlgorithm: oidcEncryption, - certificateAlgorithm: samlEncryption, - webauthnConfig: webAuthN, - httpClient: httpClient, - checkPermission: permissionCheck, - newCode: newCryptoCodeWithExpiry, - sessionTokenCreator: sessionTokenCreator(idGenerator, sessionAlg), - sessionTokenVerifier: sessionTokenVerifier, + eventstore: es, + static: staticStore, + idGenerator: idGenerator, + zitadelRoles: zitadelRoles, + externalDomain: externalDomain, + externalSecure: externalSecure, + externalPort: externalPort, + keySize: defaults.KeyConfig.Size, + certKeySize: defaults.KeyConfig.CertificateSize, + privateKeyLifetime: defaults.KeyConfig.PrivateKeyLifetime, + publicKeyLifetime: defaults.KeyConfig.PublicKeyLifetime, + certificateLifetime: defaults.KeyConfig.CertificateLifetime, + idpConfigEncryption: idpConfigEncryption, + smtpEncryption: smtpEncryption, + smsEncryption: smsEncryption, + userEncryption: userEncryption, + domainVerificationAlg: domainVerificationEncryption, + keyAlgorithm: oidcEncryption, + certificateAlgorithm: samlEncryption, + webauthnConfig: webAuthN, + httpClient: httpClient, + checkPermission: permissionCheck, + newCode: newCryptoCode, + sessionTokenCreator: sessionTokenCreator(idGenerator, sessionAlg), + sessionTokenVerifier: sessionTokenVerifier, + defaultAccessTokenLifetime: defaultAccessTokenLifetime, + defaultRefreshTokenLifetime: defaultRefreshTokenLifetime, + defaultRefreshTokenIdleLifetime: defaultRefreshTokenIdleLifetime, } instance_repo.RegisterEventMappers(repo.eventstore) @@ -124,8 +137,15 @@ func StartCommands( quota.RegisterEventMappers(repo.eventstore) session.RegisterEventMappers(repo.eventstore) idpintent.RegisterEventMappers(repo.eventstore) + authrequest.RegisterEventMappers(repo.eventstore) + oidcsession.RegisterEventMappers(repo.eventstore) + milestone.RegisterEventMappers(repo.eventstore) - repo.userPasswordAlg = crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost) + repo.codeAlg = crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost) + repo.userPasswordHasher, err = defaults.PasswordHasher.PasswordHasher() + if err != nil { + return nil, err + } repo.machineKeySize = int(defaults.SecretGenerators.MachineKeySize) repo.applicationKeySize = int(defaults.SecretGenerators.ApplicationKeySize) diff --git a/internal/command/crypto.go b/internal/command/crypto.go index e94f66463..8d145f2cc 100644 --- a/internal/command/crypto.go +++ b/internal/command/crypto.go @@ -10,15 +10,15 @@ import ( "github.com/zitadel/zitadel/internal/errors" ) -type cryptoCodeFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCodeWithExpiry, error) +type cryptoCodeFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCode, error) -type CryptoCodeWithExpiry struct { +type CryptoCode struct { Crypted *crypto.CryptoValue Plain string Expiry time.Duration } -func newCryptoCodeWithExpiry(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCodeWithExpiry, error) { +func newCryptoCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCode, error) { gen, config, err := secretGenerator(ctx, filter, typ, alg) if err != nil { return nil, err @@ -27,7 +27,7 @@ func newCryptoCodeWithExpiry(ctx context.Context, filter preparation.FilterToQue if err != nil { return nil, err } - return &CryptoCodeWithExpiry{ + return &CryptoCode{ Crypted: crypted, Plain: plain, Expiry: config.Expiry, @@ -42,14 +42,6 @@ func verifyCryptoCode(ctx context.Context, filter preparation.FilterToQueryReduc return crypto.VerifyCode(creation, expiry, crypted, plain, gen) } -func newCryptoCodeWithPlain(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (value *crypto.CryptoValue, plain string, err error) { - gen, _, err := secretGenerator(ctx, filter, typ, alg) - if err != nil { - return nil, "", err - } - return crypto.NewCode(gen) -} - func secretGenerator(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (crypto.Generator, *crypto.GeneratorConfig, error) { config, err := secretGeneratorConfig(ctx, filter, typ) if err != nil { diff --git a/internal/command/crypto_test.go b/internal/command/crypto_test.go index a846ae43a..66c2c63c5 100644 --- a/internal/command/crypto_test.go +++ b/internal/command/crypto_test.go @@ -19,8 +19,8 @@ import ( ) func mockCode(code string, exp time.Duration) cryptoCodeFunc { - return func(ctx context.Context, filter preparation.FilterToQueryReducer, _ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCodeWithExpiry, error) { - return &CryptoCodeWithExpiry{ + return func(ctx context.Context, filter preparation.FilterToQueryReducer, _ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCode, error) { + return &CryptoCode{ Crypted: &crypto.CryptoValue{ CryptoType: crypto.TypeEncryption, Algorithm: "enc", @@ -89,7 +89,7 @@ func Test_newCryptoCode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := newCryptoCodeWithExpiry(context.Background(), tt.eventstore.Filter, tt.args.typ, tt.args.alg) + got, err := newCryptoCode(context.Background(), tt.eventstore.Filter, tt.args.typ, tt.args.alg) require.ErrorIs(t, err, tt.wantErr) if tt.wantErr == nil { require.NotNil(t, got) @@ -105,7 +105,7 @@ func Test_verifyCryptoCode(t *testing.T) { es := eventstoreExpect(t, expectFilter( eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypeVerifyEmailCode)), )) - code, err := newCryptoCodeWithExpiry(context.Background(), es.Filter, domain.SecretGeneratorTypeVerifyEmailCode, crypto.CreateMockHashAlg(gomock.NewController(t))) + code, err := newCryptoCode(context.Background(), es.Filter, domain.SecretGeneratorTypeVerifyEmailCode, crypto.CreateMockHashAlg(gomock.NewController(t))) require.NoError(t, err) type args struct { diff --git a/internal/command/email.go b/internal/command/email.go index f54b3de8e..519887af6 100644 --- a/internal/command/email.go +++ b/internal/command/email.go @@ -23,6 +23,6 @@ func (e *Email) Validate() error { return e.Address.Validate() } -func (c *Commands) newEmailCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCodeWithExpiry, error) { +func (c *Commands) newEmailCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) { return c.newCode(ctx, filter, domain.SecretGeneratorTypeVerifyEmailCode, alg) } diff --git a/internal/command/instance.go b/internal/command/instance.go index 415fae3a2..ac52c351d 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -70,6 +70,7 @@ type InstanceSetup struct { AllowRegister bool AllowExternalIDP bool ForceMFA bool + ForceMFALocalOnly bool HidePasswordReset bool IgnoreUnknownUsername bool AllowDomainDiscovery bool @@ -226,6 +227,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str setup.LoginPolicy.AllowRegister, setup.LoginPolicy.AllowExternalIDP, setup.LoginPolicy.ForceMFA, + setup.LoginPolicy.ForceMFALocalOnly, setup.LoginPolicy.HidePasswordReset, setup.LoginPolicy.IgnoreUnknownUsername, setup.LoginPolicy.AllowDomainDiscovery, @@ -335,7 +337,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str } else if setup.Org.Human != nil { setup.Org.Human.ID = userID validations = append(validations, - c.AddHumanCommand(setup.Org.Human, orgID, c.userPasswordAlg, c.userEncryption, true), + c.AddHumanCommand(setup.Org.Human, orgID, c.userPasswordHasher, c.userEncryption, true), ) } @@ -501,6 +503,9 @@ func (c *Commands) ChangeSystemConfig(ctx context.Context, externalDomain string if err != nil { return err } + if len(cmds) == 0 { + continue + } _, err = c.eventstore.Push(ctx, cmds...) if err != nil { return err diff --git a/internal/command/instance_converter.go b/internal/command/instance_converter.go index d4e334ef2..6d7f60575 100644 --- a/internal/command/instance_converter.go +++ b/internal/command/instance_converter.go @@ -34,6 +34,7 @@ func writeModelToLoginPolicy(wm *LoginPolicyWriteModel) *domain.LoginPolicy { IgnoreUnknownUsernames: wm.IgnoreUnknownUsernames, AllowDomainDiscovery: wm.AllowDomainDiscovery, ForceMFA: wm.ForceMFA, + ForceMFALocalOnly: wm.ForceMFALocalOnly, PasswordlessType: wm.PasswordlessType, DefaultRedirectURI: wm.DefaultRedirectURI, PasswordCheckLifetime: wm.PasswordCheckLifetime, @@ -123,10 +124,10 @@ func writeModelToLockoutPolicy(wm *LockoutPolicyWriteModel) *domain.LockoutPolic func writeModelToPrivacyPolicy(wm *PrivacyPolicyWriteModel) *domain.PrivacyPolicy { return &domain.PrivacyPolicy{ - ObjectRoot: writeModelToObjectRoot(wm.WriteModel), - TOSLink: wm.TOSLink, - PrivacyLink: wm.PrivacyLink, - HelpLink: wm.HelpLink, + ObjectRoot: writeModelToObjectRoot(wm.WriteModel), + TOSLink: wm.TOSLink, + PrivacyLink: wm.PrivacyLink, + HelpLink: wm.HelpLink, SupportEmail: wm.SupportEmail, } } diff --git a/internal/command/instance_domain.go b/internal/command/instance_domain.go index 54e4121bc..cbf505bc7 100644 --- a/internal/command/instance_domain.go +++ b/internal/command/instance_domain.go @@ -107,6 +107,9 @@ func (c *Commands) addInstanceDomain(a *instance.Aggregate, instanceDomain strin if err != nil { return nil, err } + if consoleChangeEvent == nil { + return events, nil + } return append(events, consoleChangeEvent), nil }, nil } @@ -122,6 +125,9 @@ func (c *Commands) prepareUpdateConsoleRedirectURIs(instanceDomain string) prepa if err != nil { return nil, err } + if consoleChangeEvent == nil { + return nil, nil + } return []eventstore.Command{ consoleChangeEvent, }, nil @@ -146,6 +152,9 @@ func (c *Commands) updateConsoleRedirectURIs(ctx context.Context, filter prepara if !containsURI(appWriteModel.PostLogoutRedirectUris, postLogoutRedirectURI) { changes = append(changes, project.ChangePostLogoutRedirectURIs(append(appWriteModel.PostLogoutRedirectUris, postLogoutRedirectURI))) } + if len(changes) == 0 { + return nil, nil + } return project.NewOIDCConfigChangedEvent( ctx, ProjectAggregateFromWriteModel(&appWriteModel.WriteModel), @@ -154,17 +163,6 @@ func (c *Commands) updateConsoleRedirectURIs(ctx context.Context, filter prepara ) } -// checkUpdateConsoleRedirectURIs validates if the required console uri is present in the redirect_uris and post_logout_redirect_uris -// it will return true only if present in both list, otherwise false -func (c *Commands) checkUpdateConsoleRedirectURIs(instanceDomain string, redirectURIs, postLogoutRedirectURIs []string) bool { - redirectURI := http.BuildHTTP(instanceDomain, c.externalPort, c.externalSecure) + consoleRedirectPath - if !containsURI(redirectURIs, redirectURI) { - return false - } - postLogoutRedirectURI := http.BuildHTTP(instanceDomain, c.externalPort, c.externalSecure) + consolePostLogoutPath - return containsURI(postLogoutRedirectURIs, postLogoutRedirectURI) -} - func setPrimaryInstanceDomain(a *instance.Aggregate, instanceDomain string) preparation.Validation { return func() (preparation.CreateCommands, error) { if instanceDomain = strings.TrimSpace(instanceDomain); instanceDomain == "" { diff --git a/internal/command/instance_policy_login.go b/internal/command/instance_policy_login.go index d2fa5cb2d..d31c95f4c 100644 --- a/internal/command/instance_policy_login.go +++ b/internal/command/instance_policy_login.go @@ -234,6 +234,7 @@ func prepareChangeDefaultLoginPolicy(a *instance.Aggregate, policy *ChangeLoginP policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, + policy.ForceMFALocalOnly, policy.HidePasswordReset, policy.IgnoreUnknownUsernames, policy.AllowDomainDiscovery, @@ -260,6 +261,7 @@ func prepareAddDefaultLoginPolicy( allowRegister bool, allowExternalIDP bool, forceMFA bool, + forceMFALocalOnly bool, hidePasswordReset bool, ignoreUnknownUsernames bool, allowDomainDiscovery bool, @@ -293,6 +295,7 @@ func prepareAddDefaultLoginPolicy( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, diff --git a/internal/command/instance_policy_login_model.go b/internal/command/instance_policy_login_model.go index 3f04616aa..8d854d2b0 100644 --- a/internal/command/instance_policy_login_model.go +++ b/internal/command/instance_policy_login_model.go @@ -65,6 +65,7 @@ func (wm *InstanceLoginPolicyWriteModel) NewChangedEvent( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, @@ -92,6 +93,9 @@ func (wm *InstanceLoginPolicyWriteModel) NewChangedEvent( if wm.ForceMFA != forceMFA { changes = append(changes, policy.ChangeForceMFA(forceMFA)) } + if wm.ForceMFALocalOnly != forceMFALocalOnly { + changes = append(changes, policy.ChangeForceMFALocalOnly(forceMFALocalOnly)) + } if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType { changes = append(changes, policy.ChangePasswordlessType(passwordlessType)) } diff --git a/internal/command/instance_policy_login_test.go b/internal/command/instance_policy_login_test.go index 639fc4a65..881f1c964 100644 --- a/internal/command/instance_policy_login_test.go +++ b/internal/command/instance_policy_login_test.go @@ -73,6 +73,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -92,6 +93,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -129,6 +131,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -153,6 +156,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*10, @@ -172,6 +176,7 @@ func TestCommandSide_ChangeDefaultLoginPolicy(t *testing.T) { AllowUsernamePassword: false, AllowExternalIDP: false, ForceMFA: false, + ForceMFALocalOnly: false, HidePasswordReset: false, IgnoreUnknownUsernames: false, AllowDomainDiscovery: false, @@ -281,6 +286,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -322,6 +328,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -383,6 +390,7 @@ func TestCommandSide_AddIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -526,6 +534,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -567,6 +576,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -621,6 +631,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -680,6 +691,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -747,6 +759,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -1301,7 +1314,7 @@ func TestCommandSide_RemoveMultiFactorDefaultLoginPolicy(t *testing.T) { } } -func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, +func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allowUsernamePassword, allowExternalIDP, forceMFA, forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, disableLoginWithEmail, disableLoginWithPhone bool, passwordlessType domain.PasswordlessType, redirectURI string, @@ -1312,6 +1325,7 @@ func newDefaultLoginPolicyChangedEvent(ctx context.Context, allowRegister, allow policy.ChangeAllowRegister(allowRegister), policy.ChangeAllowExternalIDP(allowExternalIDP), policy.ChangeForceMFA(forceMFA), + policy.ChangeForceMFALocalOnly(forceMFALocalOnly), policy.ChangeAllowUserNamePassword(allowUsernamePassword), policy.ChangeHidePasswordReset(hidePasswordReset), policy.ChangeIgnoreUnknownUsernames(ignoreUnknownUsernames), diff --git a/internal/command/main_test.go b/internal/command/main_test.go index 184b0a9b0..d1a2b3de5 100644 --- a/internal/command/main_test.go +++ b/internal/command/main_test.go @@ -3,10 +3,13 @@ package command import ( "context" "database/sql" + "strings" "testing" "time" "github.com/golang/mock/gomock" + "github.com/zitadel/passwap" + "github.com/zitadel/passwap/verifier" "golang.org/x/text/language" "github.com/zitadel/zitadel/internal/crypto" @@ -16,9 +19,11 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/eventstore/repository/mock" action_repo "github.com/zitadel/zitadel/internal/repository/action" + "github.com/zitadel/zitadel/internal/repository/authrequest" "github.com/zitadel/zitadel/internal/repository/idpintent" iam_repo "github.com/zitadel/zitadel/internal/repository/instance" key_repo "github.com/zitadel/zitadel/internal/repository/keypair" + "github.com/zitadel/zitadel/internal/repository/oidcsession" "github.com/zitadel/zitadel/internal/repository/org" proj_repo "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/session" @@ -43,6 +48,8 @@ func eventstoreExpect(t *testing.T, expects ...expect) *eventstore.Eventstore { action_repo.RegisterEventMappers(es) session.RegisterEventMappers(es) idpintent.RegisterEventMappers(es) + authrequest.RegisterEventMappers(es) + oidcsession.RegisterEventMappers(es) return es } @@ -289,3 +296,38 @@ func newMockPermissionCheckNotAllowed() domain.PermissionCheck { return errors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied") } } + +type plainHasher struct { + x string // arbitrary info that triggers update when different from encoding +} + +func (h plainHasher) Hash(password string) (string, error) { + return strings.Join([]string{"", "plain", h.x, password}, "$"), nil +} + +func (h plainHasher) Verify(encoded, password string) (verifier.Result, error) { + nodes := strings.Split(encoded, "$") + if len(nodes) != 4 || nodes[1] != "plain" { + return verifier.Skip, nil + } + if nodes[3] != password { + return verifier.Fail, nil + } + if nodes[2] != h.x { + return verifier.NeedUpdate, nil + } + return verifier.OK, nil +} + +// mockPasswordHasher creates a swapper for plain (cleartext) password used in tests. +// x can be set to arbitrary info which triggers updates when different from the +// setting in the encoded hashes. (normally cost parameters) +// +// With `x` set to "foo", the following encoded string would be produced by Hash: +// $plain$foo$password +func mockPasswordHasher(x string) *crypto.PasswordHasher { + return &crypto.PasswordHasher{ + Swapper: passwap.NewSwapper(plainHasher{x: x}), + Prefixes: []string{"$plain$"}, + } +} diff --git a/internal/command/milestone.go b/internal/command/milestone.go new file mode 100644 index 000000000..f01ec6d15 --- /dev/null +++ b/internal/command/milestone.go @@ -0,0 +1,22 @@ +package command + +import ( + "context" + + "github.com/zitadel/zitadel/internal/repository/milestone" +) + +// MilestonePushed writes a new milestone.PushedEvent with a new milestone.Aggregate to the eventstore +func (c *Commands) MilestonePushed( + ctx context.Context, + msType milestone.Type, + endpoints []string, + primaryDomain string, +) error { + id, err := c.idGenerator.Next() + if err != nil { + return err + } + _, err = c.eventstore.Push(ctx, milestone.NewPushedEvent(ctx, milestone.NewAggregate(ctx, id), msType, endpoints, primaryDomain, c.externalDomain)) + return err +} diff --git a/internal/command/oidc_session.go b/internal/command/oidc_session.go new file mode 100644 index 000000000..d990d0053 --- /dev/null +++ b/internal/command/oidc_session.go @@ -0,0 +1,370 @@ +package command + +import ( + "context" + "encoding/base64" + "fmt" + "strings" + "time" + + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/id" + "github.com/zitadel/zitadel/internal/repository/authrequest" + "github.com/zitadel/zitadel/internal/repository/oidcsession" + "github.com/zitadel/zitadel/internal/repository/user" +) + +const ( + TokenDelimiter = "-" + AccessTokenPrefix = "at_" + RefreshTokenPrefix = "rt_" + oidcTokenSubjectDelimiter = ":" + oidcTokenFormat = "%s" + oidcTokenSubjectDelimiter + "%s" +) + +// AddOIDCSessionAccessToken creates a new OIDC Session, creates an access token and returns its id and expiration. +// If the underlying [AuthRequest] is a OIDC Auth Code Flow, it will set the code as exchanged. +func (c *Commands) AddOIDCSessionAccessToken(ctx context.Context, authRequestID string) (string, time.Time, error) { + cmd, err := c.newOIDCSessionAddEvents(ctx, authRequestID) + if err != nil { + return "", time.Time{}, err + } + cmd.AddSession(ctx) + if err = cmd.AddAccessToken(ctx, cmd.authRequestWriteModel.Scope); err != nil { + return "", time.Time{}, err + } + cmd.SetAuthRequestSuccessful(ctx) + accessTokenID, _, accessTokenExpiration, err := cmd.PushEvents(ctx) + return accessTokenID, accessTokenExpiration, err +} + +// AddOIDCSessionRefreshAndAccessToken creates a new OIDC Session, creates an access token and refresh token. +// It returns the access token id, expiration and the refresh token. +// If the underlying [AuthRequest] is a OIDC Auth Code Flow, it will set the code as exchanged. +func (c *Commands) AddOIDCSessionRefreshAndAccessToken(ctx context.Context, authRequestID string) (tokenID, refreshToken string, tokenExpiration time.Time, err error) { + cmd, err := c.newOIDCSessionAddEvents(ctx, authRequestID) + if err != nil { + return "", "", time.Time{}, err + } + cmd.AddSession(ctx) + if err = cmd.AddAccessToken(ctx, cmd.authRequestWriteModel.Scope); err != nil { + return "", "", time.Time{}, err + } + if err = cmd.AddRefreshToken(ctx); err != nil { + return "", "", time.Time{}, err + } + cmd.SetAuthRequestSuccessful(ctx) + return cmd.PushEvents(ctx) +} + +// ExchangeOIDCSessionRefreshAndAccessToken updates an existing OIDC Session, creates a new access and refresh token. +// It returns the access token id and expiration and the new refresh token. +func (c *Commands) ExchangeOIDCSessionRefreshAndAccessToken(ctx context.Context, oidcSessionID, refreshToken string, scope []string) (tokenID, newRefreshToken string, tokenExpiration time.Time, err error) { + cmd, err := c.newOIDCSessionUpdateEvents(ctx, oidcSessionID, refreshToken) + if err != nil { + return "", "", time.Time{}, err + } + if err = cmd.AddAccessToken(ctx, scope); err != nil { + return "", "", time.Time{}, err + } + if err = cmd.RenewRefreshToken(ctx); err != nil { + return "", "", time.Time{}, err + } + return cmd.PushEvents(ctx) +} + +// OIDCSessionByRefreshToken computes the current state of an existing OIDCSession by a refresh_token (to start a Refresh Token Grant). +// If either the session is not active, the token is invalid or expired (incl. idle expiration) an invalid refresh token error will be returned. +func (c *Commands) OIDCSessionByRefreshToken(ctx context.Context, refreshToken string) (*OIDCSessionWriteModel, error) { + oidcSessionID, refreshTokenID, err := parseRefreshToken(refreshToken) + if err != nil { + return nil, err + } + writeModel := NewOIDCSessionWriteModel(oidcSessionID, "") + err = c.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, caos_errs.ThrowPreconditionFailed(err, "OIDCS-SAF31", "Errors.OIDCSession.RefreshTokenInvalid") + } + if err = writeModel.CheckRefreshToken(refreshTokenID); err != nil { + return nil, err + } + return writeModel, nil +} + +func oidcSessionTokenIDsFromToken(token string) (oidcSessionID, refreshTokenID, accessTokenID string, err error) { + split := strings.Split(token, TokenDelimiter) + if len(split) != 2 { + return "", "", "", caos_errs.ThrowPreconditionFailed(nil, "OIDCS-S87kl", "Errors.OIDCSession.Token.Invalid") + } + if strings.HasPrefix(split[1], RefreshTokenPrefix) { + return split[0], split[1], "", nil + } + if strings.HasPrefix(split[1], AccessTokenPrefix) { + return split[0], "", split[1], nil + } + return "", "", "", caos_errs.ThrowPreconditionFailed(nil, "OIDCS-S87kl", "Errors.OIDCSession.Token.Invalid") +} + +// RevokeOIDCSessionToken revokes an access_token or refresh_token +// if the OIDCSession cannot be retrieved by the provided token, is not active or if the token is already revoked, +// then no error will be returned. +// The only possible error (except db connection or other internal errors) occurs if a client tries to revoke a token, +// which was not part of the audience. +func (c *Commands) RevokeOIDCSessionToken(ctx context.Context, token, clientID string) (err error) { + oidcSessionID, refreshTokenID, accessTokenID, err := oidcSessionTokenIDsFromToken(token) + if err != nil { + logging.WithError(err).Info("token revocation with invalid token format") + return nil + } + writeModel := NewOIDCSessionWriteModel(oidcSessionID, "") + err = c.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return caos_errs.ThrowInternal(err, "OIDCS-NB3t2", "Errors.Internal") + } + if err = writeModel.CheckClient(clientID); err != nil { + return err + } + if refreshTokenID != "" { + if err = writeModel.CheckRefreshToken(refreshTokenID); err != nil { + logging.WithFields("oidcSessionID", oidcSessionID, "refreshTokenID", refreshTokenID).WithError(err). + Info("refresh token revocation with invalid token") + return nil + } + return c.pushAppendAndReduce(ctx, writeModel, oidcsession.NewRefreshTokenRevokedEvent(ctx, writeModel.aggregate)) + } + if err = writeModel.CheckAccessToken(accessTokenID); err != nil { + logging.WithFields("oidcSessionID", oidcSessionID, "accessTokenID", accessTokenID).WithError(err). + Info("access token revocation with invalid token") + return nil + } + return c.pushAppendAndReduce(ctx, writeModel, oidcsession.NewAccessTokenRevokedEvent(ctx, writeModel.aggregate)) +} + +func (c *Commands) newOIDCSessionAddEvents(ctx context.Context, authRequestID string) (*OIDCSessionEvents, error) { + authRequestWriteModel, err := c.getAuthRequestWriteModel(ctx, authRequestID) + if err != nil { + return nil, err + } + if err = authRequestWriteModel.CheckAuthenticated(); err != nil { + return nil, err + } + sessionWriteModel := NewSessionWriteModel(authRequestWriteModel.SessionID, authz.GetCtxData(ctx).OrgID) + err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel) + if err != nil { + return nil, err + } + if sessionWriteModel.State != domain.SessionStateActive { + return nil, caos_errs.ThrowPreconditionFailed(nil, "OIDCS-sjkl3", "Errors.Session.Terminated") + } + resourceOwner, err := c.getResourceOwnerOfSessionUser(ctx, sessionWriteModel.UserID, sessionWriteModel.InstanceID) + if err != nil { + return nil, err + } + accessTokenLifetime, refreshTokenLifeTime, refreshTokenIdleLifetime, err := c.tokenTokenLifetimes(ctx) + if err != nil { + return nil, err + } + sessionID, err := c.idGenerator.Next() + if err != nil { + return nil, err + } + sessionID = IDPrefixV2 + sessionID + return &OIDCSessionEvents{ + eventstore: c.eventstore, + idGenerator: c.idGenerator, + encryptionAlg: c.keyAlgorithm, + oidcSessionWriteModel: NewOIDCSessionWriteModel(sessionID, resourceOwner), + sessionWriteModel: sessionWriteModel, + authRequestWriteModel: authRequestWriteModel, + accessTokenLifetime: accessTokenLifetime, + refreshTokenLifeTime: refreshTokenLifeTime, + refreshTokenIdleLifetime: refreshTokenIdleLifetime, + }, nil +} + +func (c *Commands) getResourceOwnerOfSessionUser(ctx context.Context, userID, instanceID string) (string, error) { + events, err := c.eventstore.Filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + InstanceID(instanceID). + AllowTimeTravel(). + OrderAsc(). + Limit(1). + AddQuery(). + AggregateTypes(user.AggregateType). + AggregateIDs(userID). + Builder()) + if err != nil || len(events) != 1 { + return "", caos_errs.ThrowInternal(err, "OIDCS-sferh", "Errors.Internal") + } + return events[0].Aggregate().ResourceOwner, nil +} + +func (c *Commands) decryptRefreshToken(refreshToken string) (refreshTokenID string, err error) { + decoded, err := base64.RawURLEncoding.DecodeString(refreshToken) + if err != nil { + return "", err + } + decrypted, err := c.keyAlgorithm.DecryptString(decoded, c.keyAlgorithm.EncryptionKeyID()) + if err != nil { + return "", err + } + _, refreshTokenID, err = parseRefreshToken(decrypted) + return refreshTokenID, err +} + +func parseRefreshToken(refreshToken string) (oidcSessionID, refreshTokenID string, err error) { + split := strings.Split(refreshToken, TokenDelimiter) + if len(split) < 2 || !strings.HasPrefix(split[1], RefreshTokenPrefix) { + return "", "", caos_errs.ThrowPreconditionFailed(nil, "OIDCS-JOI23", "Errors.OIDCSession.RefreshTokenInvalid") + } + // the oidc library requires that every token has the format of : + // the V2 tokens don't use the userID anymore, so let's just remove it + return split[0], strings.Split(split[1], oidcTokenSubjectDelimiter)[0], nil +} + +func (c *Commands) newOIDCSessionUpdateEvents(ctx context.Context, oidcSessionID, refreshToken string) (*OIDCSessionEvents, error) { + refreshTokenID, err := c.decryptRefreshToken(refreshToken) + if err != nil { + return nil, err + } + sessionWriteModel := NewOIDCSessionWriteModel(oidcSessionID, "") + if err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel); err != nil { + return nil, err + } + if err = sessionWriteModel.CheckRefreshToken(refreshTokenID); err != nil { + return nil, err + } + accessTokenLifetime, refreshTokenLifeTime, refreshTokenIdleLifetime, err := c.tokenTokenLifetimes(ctx) + if err != nil { + return nil, err + } + return &OIDCSessionEvents{ + eventstore: c.eventstore, + idGenerator: c.idGenerator, + encryptionAlg: c.keyAlgorithm, + oidcSessionWriteModel: sessionWriteModel, + accessTokenLifetime: accessTokenLifetime, + refreshTokenLifeTime: refreshTokenLifeTime, + refreshTokenIdleLifetime: refreshTokenIdleLifetime, + }, nil +} + +type OIDCSessionEvents struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + encryptionAlg crypto.EncryptionAlgorithm + events []eventstore.Command + oidcSessionWriteModel *OIDCSessionWriteModel + sessionWriteModel *SessionWriteModel + authRequestWriteModel *AuthRequestWriteModel + accessTokenLifetime time.Duration + refreshTokenLifeTime time.Duration + refreshTokenIdleLifetime time.Duration + + // accessTokenID is set by the command + accessTokenID string + + // refreshToken is set by the command + refreshToken string +} + +func (c *OIDCSessionEvents) AddSession(ctx context.Context) { + c.events = append(c.events, oidcsession.NewAddedEvent( + ctx, + c.oidcSessionWriteModel.aggregate, + c.sessionWriteModel.UserID, + c.sessionWriteModel.AggregateID, + c.authRequestWriteModel.ClientID, + c.authRequestWriteModel.Audience, + c.authRequestWriteModel.Scope, + c.sessionWriteModel.AuthMethodTypes(), + c.sessionWriteModel.AuthenticationTime(), + )) +} + +func (c *OIDCSessionEvents) SetAuthRequestSuccessful(ctx context.Context) { + c.events = append(c.events, authrequest.NewSucceededEvent(ctx, c.authRequestWriteModel.aggregate)) +} + +func (c *OIDCSessionEvents) AddAccessToken(ctx context.Context, scope []string) error { + accessTokenID, err := c.idGenerator.Next() + if err != nil { + return err + } + c.accessTokenID = AccessTokenPrefix + accessTokenID + c.events = append(c.events, oidcsession.NewAccessTokenAddedEvent(ctx, c.oidcSessionWriteModel.aggregate, c.accessTokenID, scope, c.accessTokenLifetime)) + return nil +} + +func (c *OIDCSessionEvents) AddRefreshToken(ctx context.Context) (err error) { + var refreshTokenID string + refreshTokenID, c.refreshToken, err = c.generateRefreshToken(c.sessionWriteModel.UserID) + if err != nil { + return err + } + c.events = append(c.events, oidcsession.NewRefreshTokenAddedEvent(ctx, c.oidcSessionWriteModel.aggregate, refreshTokenID, c.refreshTokenLifeTime, c.refreshTokenIdleLifetime)) + return nil +} + +func (c *OIDCSessionEvents) RenewRefreshToken(ctx context.Context) (err error) { + var refreshTokenID string + refreshTokenID, c.refreshToken, err = c.generateRefreshToken(c.oidcSessionWriteModel.UserID) + if err != nil { + return err + } + c.events = append(c.events, oidcsession.NewRefreshTokenRenewedEvent(ctx, c.oidcSessionWriteModel.aggregate, refreshTokenID, c.refreshTokenIdleLifetime)) + return nil +} + +func (c *OIDCSessionEvents) generateRefreshToken(userID string) (refreshTokenID, refreshToken string, err error) { + refreshTokenID, err = c.idGenerator.Next() + if err != nil { + return "", "", err + } + refreshTokenID = RefreshTokenPrefix + refreshTokenID + token, err := c.encryptionAlg.Encrypt([]byte(fmt.Sprintf(oidcTokenFormat, c.oidcSessionWriteModel.OIDCRefreshTokenID(refreshTokenID), userID))) + if err != nil { + return "", "", err + } + return refreshTokenID, base64.RawURLEncoding.EncodeToString(token), nil +} + +func (c *OIDCSessionEvents) PushEvents(ctx context.Context) (accessTokenID string, refreshToken string, accessTokenExpiration time.Time, err error) { + pushedEvents, err := c.eventstore.Push(ctx, c.events...) + if err != nil { + return "", "", time.Time{}, err + } + err = AppendAndReduce(c.oidcSessionWriteModel, pushedEvents...) + if err != nil { + return "", "", time.Time{}, err + } + // prefix the returned id with the oidcSessionID so that we can retrieve it later on + // we need to use `-` as a delimiter because the OIDC library uses `:` and will check for a length of 2 parts + return c.oidcSessionWriteModel.AggregateID + TokenDelimiter + c.accessTokenID, c.refreshToken, c.oidcSessionWriteModel.AccessTokenExpiration, nil +} + +func (c *Commands) tokenTokenLifetimes(ctx context.Context) (accessTokenLifetime time.Duration, refreshTokenLifetime time.Duration, refreshTokenIdleLifetime time.Duration, err error) { + oidcSettings := NewInstanceOIDCSettingsWriteModel(ctx) + err = c.eventstore.FilterToQueryReducer(ctx, oidcSettings) + if err != nil { + return 0, 0, 0, err + } + accessTokenLifetime = c.defaultAccessTokenLifetime + refreshTokenLifetime = c.defaultRefreshTokenLifetime + refreshTokenIdleLifetime = c.defaultRefreshTokenIdleLifetime + if oidcSettings.AccessTokenLifetime > 0 { + accessTokenLifetime = oidcSettings.AccessTokenLifetime + } + if oidcSettings.RefreshTokenExpiration > 0 { + refreshTokenLifetime = oidcSettings.RefreshTokenExpiration + } + if oidcSettings.RefreshTokenIdleExpiration > 0 { + refreshTokenIdleLifetime = oidcSettings.RefreshTokenIdleExpiration + } + return accessTokenLifetime, refreshTokenLifetime, refreshTokenIdleLifetime, nil +} diff --git a/internal/command/oidc_session_model.go b/internal/command/oidc_session_model.go new file mode 100644 index 000000000..94725d933 --- /dev/null +++ b/internal/command/oidc_session_model.go @@ -0,0 +1,167 @@ +package command + +import ( + "time" + + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/oidcsession" +) + +type OIDCSessionWriteModel struct { + eventstore.WriteModel + + UserID string + SessionID string + ClientID string + Audience []string + Scope []string + AuthMethods []domain.UserAuthMethodType + AuthTime time.Time + State domain.OIDCSessionState + AccessTokenID string + AccessTokenCreation time.Time + AccessTokenExpiration time.Time + RefreshTokenID string + RefreshToken string + RefreshTokenExpiration time.Time + RefreshTokenIdleExpiration time.Time + + aggregate *eventstore.Aggregate +} + +func NewOIDCSessionWriteModel(id string, resourceOwner string) *OIDCSessionWriteModel { + return &OIDCSessionWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: id, + ResourceOwner: resourceOwner, + }, + aggregate: &oidcsession.NewAggregate(id, resourceOwner).Aggregate, + } +} + +func (wm *OIDCSessionWriteModel) Reduce() error { + for _, event := range wm.Events { + switch e := event.(type) { + case *oidcsession.AddedEvent: + wm.reduceAdded(e) + case *oidcsession.AccessTokenAddedEvent: + wm.reduceAccessTokenAdded(e) + case *oidcsession.AccessTokenRevokedEvent: + wm.reduceAccessTokenRevoked(e) + case *oidcsession.RefreshTokenAddedEvent: + wm.reduceRefreshTokenAdded(e) + case *oidcsession.RefreshTokenRenewedEvent: + wm.reduceRefreshTokenRenewed(e) + case *oidcsession.RefreshTokenRevokedEvent: + wm.reduceRefreshTokenRevoked(e) + } + } + return wm.WriteModel.Reduce() +} + +func (wm *OIDCSessionWriteModel) Query() *eventstore.SearchQueryBuilder { + query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AddQuery(). + AggregateTypes(oidcsession.AggregateType). + AggregateIDs(wm.AggregateID). + EventTypes( + oidcsession.AddedType, + oidcsession.AccessTokenAddedType, + oidcsession.RefreshTokenAddedType, + oidcsession.RefreshTokenRenewedType, + oidcsession.RefreshTokenRevokedType, + ). + Builder() + + if wm.ResourceOwner != "" { + query.ResourceOwner(wm.ResourceOwner) + } + return query +} + +func (wm *OIDCSessionWriteModel) reduceAdded(e *oidcsession.AddedEvent) { + wm.UserID = e.UserID + wm.SessionID = e.SessionID + wm.ClientID = e.ClientID + wm.Audience = e.Audience + wm.Scope = e.Scope + wm.AuthMethods = e.AuthMethods + wm.AuthTime = e.AuthTime + wm.State = domain.OIDCSessionStateActive + // the write model might be initialized without resource owner, + // so update the aggregate + if wm.ResourceOwner == "" { + wm.aggregate = &oidcsession.NewAggregate(wm.AggregateID, e.Aggregate().ResourceOwner).Aggregate + } +} + +func (wm *OIDCSessionWriteModel) reduceAccessTokenAdded(e *oidcsession.AccessTokenAddedEvent) { + wm.AccessTokenID = e.ID + wm.AccessTokenExpiration = e.CreationDate().Add(e.Lifetime) +} + +func (wm *OIDCSessionWriteModel) reduceAccessTokenRevoked(e *oidcsession.AccessTokenRevokedEvent) { + wm.AccessTokenID = "" + wm.AccessTokenExpiration = e.CreationDate() +} + +func (wm *OIDCSessionWriteModel) reduceRefreshTokenAdded(e *oidcsession.RefreshTokenAddedEvent) { + wm.RefreshTokenID = e.ID + wm.RefreshTokenExpiration = e.CreationDate().Add(e.Lifetime) + wm.RefreshTokenIdleExpiration = e.CreationDate().Add(e.IdleLifetime) +} + +func (wm *OIDCSessionWriteModel) reduceRefreshTokenRenewed(e *oidcsession.RefreshTokenRenewedEvent) { + wm.RefreshTokenID = e.ID + wm.RefreshTokenIdleExpiration = e.CreationDate().Add(e.IdleLifetime) +} + +func (wm *OIDCSessionWriteModel) reduceRefreshTokenRevoked(e *oidcsession.RefreshTokenRevokedEvent) { + wm.RefreshTokenID = "" + wm.RefreshTokenExpiration = e.CreationDate() + wm.RefreshTokenIdleExpiration = e.CreationDate() + wm.AccessTokenID = "" + wm.AccessTokenExpiration = e.CreationDate() +} + +func (wm *OIDCSessionWriteModel) CheckRefreshToken(refreshTokenID string) error { + if wm.State != domain.OIDCSessionStateActive { + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-s3hjk", "Errors.OIDCSession.RefreshTokenInvalid") + } + if wm.RefreshTokenID != refreshTokenID { + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-28ubl", "Errors.OIDCSession.RefreshTokenInvalid") + } + now := time.Now() + if wm.RefreshTokenExpiration.Before(now) || wm.RefreshTokenIdleExpiration.Before(now) { + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-3jt2w", "Errors.OIDCSession.RefreshTokenInvalid") + } + return nil +} + +func (wm *OIDCSessionWriteModel) CheckAccessToken(accessTokenID string) error { + if wm.State != domain.OIDCSessionStateActive { + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-KL2pk", "Errors.OIDCSession.Token.Invalid") + } + if wm.AccessTokenID != accessTokenID { + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-JLKW2", "Errors.OIDCSession.Token.Invalid") + } + if wm.AccessTokenExpiration.Before(time.Now()) { + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-3j3md", "Errors.OIDCSession.Token.Invalid") + } + return nil +} + +func (wm *OIDCSessionWriteModel) CheckClient(clientID string) error { + for _, aud := range wm.Audience { + if aud == clientID { + return nil + } + } + return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-SKjl3", "Errors.OIDCSession.InvalidClient") +} + +func (wm *OIDCSessionWriteModel) OIDCRefreshTokenID(refreshTokenID string) string { + return wm.AggregateID + TokenDelimiter + refreshTokenID +} diff --git a/internal/command/oidc_session_test.go b/internal/command/oidc_session_test.go new file mode 100644 index 000000000..b8a3a462e --- /dev/null +++ b/internal/command/oidc_session_test.go @@ -0,0 +1,1014 @@ +package command + +import ( + "context" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/text/language" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/id" + "github.com/zitadel/zitadel/internal/id/mock" + "github.com/zitadel/zitadel/internal/repository/authrequest" + "github.com/zitadel/zitadel/internal/repository/oidcsession" + "github.com/zitadel/zitadel/internal/repository/session" + "github.com/zitadel/zitadel/internal/repository/user" +) + +var ( + testNow = time.Now() + tokenCreationNow = time.Time{} +) + +func TestCommands_AddOIDCSessionAccessToken(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + defaultAccessTokenLifetime time.Duration + defaultRefreshTokenLifetime time.Duration + defaultRefreshTokenIdleLifetime time.Duration + keyAlgorithm crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + authRequestID string + } + type res struct { + id string + expiration time.Time + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "unauthenticated error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + authRequestID: "V2_authRequestID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "AUTHR-SF2r2", "Errors.AuthRequest.NotAuthenticated"), + }, + }, + { + "inactive session error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + eventFromEventPusher( + authrequest.NewSessionLinkedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + ), + eventFromEventPusher( + authrequest.NewCodeAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + eventFromEventPusher( + authrequest.NewCodeExchangedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + ), + expectFilter(), // inactive session + ), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + authRequestID: "V2_authRequestID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-sjkl3", "Errors.Session.Terminated"), + }, + }, + { + "add successful", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + eventFromEventPusher( + authrequest.NewSessionLinkedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + ), + eventFromEventPusher( + authrequest.NewCodeAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + eventFromEventPusher( + authrequest.NewCodeExchangedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + ), + expectFilter( + eventFromEventPusher( + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, "domain.tld"), + ), + eventFromEventPusher( + session.NewUserCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, + "userID", testNow), + ), + eventFromEventPusher( + session.NewPasswordCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, + testNow), + ), + ), + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate, + "username", "firstName", "lastName", "", "", language.English, domain.GenderUnspecified, "", false, + ), + ), + ), + expectFilter(), // token lifetime + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid"}, time.Hour), + ), + eventFromEventPusherWithInstanceID("instanceID", + authrequest.NewSucceededEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + }, + ), + ), + idGenerator: mock.NewIDGeneratorExpectIDs(t, "oidcSessionID", "accessTokenID"), + defaultAccessTokenLifetime: time.Hour, + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + authRequestID: "V2_authRequestID", + }, + res{ + id: "V2_oidcSessionID-at_accessTokenID", + expiration: tokenCreationNow.Add(time.Hour), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + defaultAccessTokenLifetime: tt.fields.defaultAccessTokenLifetime, + defaultRefreshTokenLifetime: tt.fields.defaultRefreshTokenLifetime, + defaultRefreshTokenIdleLifetime: tt.fields.defaultRefreshTokenIdleLifetime, + keyAlgorithm: tt.fields.keyAlgorithm, + } + gotID, gotExpiration, err := c.AddOIDCSessionAccessToken(tt.args.ctx, tt.args.authRequestID) + assert.Equal(t, tt.res.id, gotID) + assert.Equal(t, tt.res.expiration, gotExpiration) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommands_AddOIDCSessionRefreshAndAccessToken(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + defaultAccessTokenLifetime time.Duration + defaultRefreshTokenLifetime time.Duration + defaultRefreshTokenIdleLifetime time.Duration + keyAlgorithm crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + authRequestID string + } + type res struct { + id string + refreshToken string + expiration time.Time + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "unauthenticated error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + authRequestID: "V2_authRequestID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "AUTHR-SF2r2", "Errors.AuthRequest.NotAuthenticated"), + }, + }, + { + "inactive session error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid", "offline_access"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + eventFromEventPusher( + authrequest.NewSessionLinkedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + ), + eventFromEventPusher( + authrequest.NewCodeAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + eventFromEventPusher( + authrequest.NewCodeExchangedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + ), + expectFilter(), // inactive session + ), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + authRequestID: "V2_authRequestID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-sjkl3", "Errors.Session.Terminated"), + }, + }, + { + "add successful", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + authrequest.NewAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "loginClient", + "clientID", + "redirectURI", + "state", + "nonce", + []string{"openid", "offline_access"}, + []string{"audience"}, + domain.OIDCResponseTypeCode, + &domain.OIDCCodeChallenge{ + Challenge: "challenge", + Method: domain.CodeChallengeMethodS256, + }, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + ), + ), + eventFromEventPusher( + authrequest.NewSessionLinkedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate, + "sessionID", + "userID", + testNow, + []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + ), + ), + eventFromEventPusher( + authrequest.NewCodeAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + eventFromEventPusher( + authrequest.NewCodeExchangedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + ), + expectFilter( + eventFromEventPusher( + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, "domain.tld"), + ), + eventFromEventPusher( + session.NewUserCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, + "userID", testNow), + ), + eventFromEventPusher( + session.NewPasswordCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, + testNow), + ), + ), + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate, + "username", "firstName", "lastName", "", "", language.English, domain.GenderUnspecified, "", false, + ), + ), + ), + expectFilter(), // token lifetime + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "offline_access"}, time.Hour), + ), + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + eventFromEventPusherWithInstanceID("instanceID", + authrequest.NewSucceededEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate), + ), + }, + ), + ), + idGenerator: mock.NewIDGeneratorExpectIDs(t, "oidcSessionID", "accessTokenID", "refreshTokenID"), + defaultAccessTokenLifetime: time.Hour, + defaultRefreshTokenLifetime: 7 * 24 * time.Hour, + defaultRefreshTokenIdleLifetime: 24 * time.Hour, + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + authRequestID: "V2_authRequestID", + }, + res{ + id: "V2_oidcSessionID-at_accessTokenID", + refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDp1c2VySUQ", //V2_oidcSessionID-rt_refreshTokenID:userID + expiration: tokenCreationNow.Add(time.Hour), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + defaultAccessTokenLifetime: tt.fields.defaultAccessTokenLifetime, + defaultRefreshTokenLifetime: tt.fields.defaultRefreshTokenLifetime, + defaultRefreshTokenIdleLifetime: tt.fields.defaultRefreshTokenIdleLifetime, + keyAlgorithm: tt.fields.keyAlgorithm, + } + gotID, gotRefreshToken, gotExpiration, err := c.AddOIDCSessionRefreshAndAccessToken(tt.args.ctx, tt.args.authRequestID) + assert.Equal(t, tt.res.id, gotID) + assert.Equal(t, tt.res.refreshToken, gotRefreshToken) + assert.Equal(t, tt.res.expiration, gotExpiration) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommands_ExchangeOIDCSessionRefreshAndAccessToken(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + defaultAccessTokenLifetime time.Duration + defaultRefreshTokenLifetime time.Duration + defaultRefreshTokenIdleLifetime time.Duration + keyAlgorithm crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + oidcSessionID string + refreshToken string + scope []string + } + type res struct { + id string + refreshToken string + expiration time.Time + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid refresh token format error", + fields{ + eventstore: eventstoreExpect(t), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + oidcSessionID: "V2_oidcSessionID", + refreshToken: "aW52YWxpZA", // invalid + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-JOI23", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "inactive session error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + oidcSessionID: "V2_oidcSessionID", + refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDp1c2VySUQ", //V2_oidcSessionID:rt_refreshTokenID:userID + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-s3hjk", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "invalid refresh token error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusher( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + oidcSessionID: "V2_oidcSessionID", + refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDp1c2VySUQ", //V2_oidcSessionID:rt_refreshTokenID:userID + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-28ubl", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "expired refresh token error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusher( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + eventFromEventPusher( + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + oidcSessionID: "V2_oidcSessionID", + refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDp1c2VySUQ", //V2_oidcSessionID:rt_refreshTokenID:userID + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-3jt2w", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "refresh successful", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusherWithCreationDateNow( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + ), + expectFilter(), // token lifetime + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "offline_access"}, time.Hour), + ), + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewRefreshTokenRenewedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID2", 24*time.Hour), + ), + }, + ), + ), + idGenerator: mock.NewIDGeneratorExpectIDs(t, "accessTokenID", "refreshTokenID2"), + defaultAccessTokenLifetime: time.Hour, + defaultRefreshTokenLifetime: 7 * 24 * time.Hour, + defaultRefreshTokenIdleLifetime: 24 * time.Hour, + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + oidcSessionID: "V2_oidcSessionID", + refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDp1c2VySUQ", //V2_oidcSessionID:rt_refreshTokenID:userID + scope: []string{"openid", "offline_access"}, + }, + res{ + id: "V2_oidcSessionID-at_accessTokenID", + refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDI6dXNlcklE", // V2_oidcSessionID-rt_refreshTokenID2:userID% + expiration: time.Time{}.Add(time.Hour), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + defaultAccessTokenLifetime: tt.fields.defaultAccessTokenLifetime, + defaultRefreshTokenLifetime: tt.fields.defaultRefreshTokenLifetime, + defaultRefreshTokenIdleLifetime: tt.fields.defaultRefreshTokenIdleLifetime, + keyAlgorithm: tt.fields.keyAlgorithm, + } + gotID, gotRefreshToken, gotExpiration, err := c.ExchangeOIDCSessionRefreshAndAccessToken(tt.args.ctx, tt.args.oidcSessionID, tt.args.refreshToken, tt.args.scope) + assert.Equal(t, tt.res.id, gotID) + assert.Equal(t, tt.res.refreshToken, gotRefreshToken) + assert.Equal(t, tt.res.expiration, gotExpiration) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommands_OIDCSessionByRefreshToken(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + defaultAccessTokenLifetime time.Duration + defaultRefreshTokenLifetime time.Duration + defaultRefreshTokenIdleLifetime time.Duration + keyAlgorithm crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + refreshToken string + } + type res struct { + model *OIDCSessionWriteModel + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid refresh token format error", + fields{ + eventstore: eventstoreExpect(t), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + refreshToken: "invalid", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-JOI23", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "inactive session error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter(), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + refreshToken: "V2_oidcSessionID-rt_refreshTokenID:userID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-s3hjk", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "invalid refresh token error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusher( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + refreshToken: "V2_oidcSessionID-rt_refreshTokenID:userID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-28ubl", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "expired refresh token error", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusher( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + eventFromEventPusher( + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + refreshToken: "V2_oidcSessionID-rt_refreshTokenID:userID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-3jt2w", "Errors.OIDCSession.RefreshTokenInvalid"), + }, + }, + { + "get successful", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusherWithCreationDateNow( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + refreshToken: "V2_oidcSessionID-rt_refreshTokenID:userID", + }, + res{ + model: &OIDCSessionWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: "V2_oidcSessionID", + ChangeDate: testNow, + }, + UserID: "userID", + SessionID: "sessionID", + ClientID: "clientID", + Audience: []string{"audience"}, + Scope: []string{"openid", "profile", "offline_access"}, + AuthMethods: []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, + AuthTime: testNow, + State: domain.OIDCSessionStateActive, + RefreshTokenID: "rt_refreshTokenID", + RefreshTokenExpiration: testNow.Add(7 * 24 * time.Hour), + RefreshTokenIdleExpiration: testNow.Add(24 * time.Hour), + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + defaultAccessTokenLifetime: tt.fields.defaultAccessTokenLifetime, + defaultRefreshTokenLifetime: tt.fields.defaultRefreshTokenLifetime, + defaultRefreshTokenIdleLifetime: tt.fields.defaultRefreshTokenIdleLifetime, + keyAlgorithm: tt.fields.keyAlgorithm, + } + got, err := c.OIDCSessionByRefreshToken(tt.args.ctx, tt.args.refreshToken) + require.ErrorIs(t, err, tt.res.err) + if tt.res.err == nil { + assert.WithinRange(t, got.ChangeDate, tt.res.model.ChangeDate.Add(-2*time.Second), tt.res.model.ChangeDate.Add(2*time.Second)) + assert.Equal(t, tt.res.model.AggregateID, got.AggregateID) + assert.Equal(t, tt.res.model.UserID, got.UserID) + assert.Equal(t, tt.res.model.SessionID, got.SessionID) + assert.Equal(t, tt.res.model.ClientID, got.ClientID) + assert.Equal(t, tt.res.model.Audience, got.Audience) + assert.Equal(t, tt.res.model.Scope, got.Scope) + assert.Equal(t, tt.res.model.AuthMethods, got.AuthMethods) + assert.WithinRange(t, got.AuthTime, tt.res.model.AuthTime.Add(-2*time.Second), tt.res.model.AuthTime.Add(2*time.Second)) + assert.Equal(t, tt.res.model.State, got.State) + assert.Equal(t, tt.res.model.RefreshTokenID, got.RefreshTokenID) + assert.WithinRange(t, got.RefreshTokenExpiration, tt.res.model.RefreshTokenExpiration.Add(-2*time.Second), tt.res.model.RefreshTokenExpiration.Add(2*time.Second)) + assert.WithinRange(t, got.RefreshTokenIdleExpiration, tt.res.model.RefreshTokenIdleExpiration.Add(-2*time.Second), tt.res.model.RefreshTokenIdleExpiration.Add(2*time.Second)) + } + }) + } +} + +func TestCommands_RevokeOIDCSessionToken(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + keyAlgorithm crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + token string + clientID string + } + type res struct { + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + "invalid token", + fields{ + eventstore: eventstoreExpect(t), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "invalid", + }, + res{ + err: nil, + }, + }, + { + "refresh_token inactive", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"clientID"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "V2_oidcSessionID-rt_refreshTokenID", + clientID: "clientID", + }, + res{ + err: nil, + }, + }, + { + "refresh_token invalid client", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "otherClientID", []string{"otherClientID"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "V2_oidcSessionID-rt_refreshTokenID", + clientID: "clientID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-SKjl3", "Errors.OIDCSession.InvalidClient"), + }, + }, + { + "refresh_token revoked", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"clientID"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + ), + expectPush([]*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewRefreshTokenRevokedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate), + ), + }), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "V2_oidcSessionID-rt_refreshTokenID", + clientID: "clientID", + }, + res{ + err: nil, + }, + }, + { + "access_token inactive session", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"clientID"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "V2_oidcSessionID-at_accessTokenID", + clientID: "clientID", + }, + res{ + err: nil, + }, + }, + { + "access_token invalid client", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "otherClientID", []string{"otherClientID"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + ), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "V2_oidcSessionID-at_accessTokenID", + clientID: "clientID", + }, + res{ + err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-SKjl3", "Errors.OIDCSession.InvalidClient"), + }, + }, + { + "access_token revoked", + fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "userID", "sessionID", "clientID", []string{"clientID"}, []string{"openid", "profile", "offline_access"}, []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour), + ), + eventFromEventPusherWithCreationDateNow( + oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate, + "rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour), + ), + ), + expectPush([]*repository.Event{ + eventFromEventPusherWithInstanceID("instanceID", + oidcsession.NewAccessTokenRevokedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate), + ), + }), + ), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args{ + ctx: authz.WithInstanceID(context.Background(), "instanceID"), + token: "V2_oidcSessionID-at_accessTokenID", + clientID: "clientID", + }, + res{ + err: nil, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Commands{ + eventstore: tt.fields.eventstore, + keyAlgorithm: tt.fields.keyAlgorithm, + } + err := c.RevokeOIDCSessionToken(tt.args.ctx, tt.args.token, tt.args.clientID) + require.ErrorIs(t, err, tt.res.err) + }) + } +} diff --git a/internal/command/org.go b/internal/command/org.go index c9fd3dbd4..ba64dccb5 100644 --- a/internal/command/org.go +++ b/internal/command/org.go @@ -42,7 +42,7 @@ func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID strin var pat *PersonalAccessToken if o.Human != nil { o.Human.ID = userID - validations = append(validations, c.AddHumanCommand(o.Human, orgID, c.userPasswordAlg, c.userEncryption, true)) + validations = append(validations, c.AddHumanCommand(o.Human, orgID, c.userPasswordHasher, c.userEncryption, true)) } else if o.Machine != nil { validations = append(validations, AddMachineCommand(userAgg, o.Machine.Machine)) if o.Machine.Pat != nil { diff --git a/internal/command/org_domain_test.go b/internal/command/org_domain_test.go index 230fc5601..feb737cde 100644 --- a/internal/command/org_domain_test.go +++ b/internal/command/org_domain_test.go @@ -653,7 +653,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) { }, res: res{ wantToken: "a", - wantURL: "https://domain.ch/.well-known/zitadel-challenge/a", + wantURL: "https://domain.ch/.well-known/zitadel-challenge/a.txt", }, }, } diff --git a/internal/command/org_policy_login.go b/internal/command/org_policy_login.go index b8e551b25..ddfb9169d 100644 --- a/internal/command/org_policy_login.go +++ b/internal/command/org_policy_login.go @@ -21,6 +21,7 @@ type AddLoginPolicy struct { AllowExternalIDP bool IDPProviders []*AddLoginPolicyIDP ForceMFA bool + ForceMFALocalOnly bool SecondFactors []domain.SecondFactorType MultiFactors []domain.MultiFactorType PasswordlessType domain.PasswordlessType @@ -47,6 +48,7 @@ type ChangeLoginPolicy struct { AllowRegister bool AllowExternalIDP bool ForceMFA bool + ForceMFALocalOnly bool PasswordlessType domain.PasswordlessType HidePasswordReset bool IgnoreUnknownUsernames bool @@ -425,6 +427,7 @@ func prepareAddLoginPolicy(a *org.Aggregate, policy *AddLoginPolicy) preparation policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, + policy.ForceMFALocalOnly, policy.HidePasswordReset, policy.IgnoreUnknownUsernames, policy.AllowDomainDiscovery, diff --git a/internal/command/org_policy_login_test.go b/internal/command/org_policy_login_test.go index e4a3c0a2f..f7d1accfa 100644 --- a/internal/command/org_policy_login_test.go +++ b/internal/command/org_policy_login_test.go @@ -61,6 +61,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { true, true, true, + true, false, false, domain.PasswordlessTypeAllowed, @@ -83,6 +84,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, PasswordlessType: domain.PasswordlessTypeAllowed, @@ -118,6 +120,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -139,6 +142,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -174,6 +178,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -213,6 +218,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -246,6 +252,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -285,6 +292,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -341,6 +349,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -369,6 +378,7 @@ func TestCommandSide_AddLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -450,6 +460,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, DisableLoginWithEmail: true, @@ -480,6 +491,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -500,6 +512,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDP: true, ForceMFA: true, + ForceMFALocalOnly: true, HidePasswordReset: true, IgnoreUnknownUsernames: true, AllowDomainDiscovery: true, @@ -536,6 +549,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "https://example.com/redirect", time.Hour*1, @@ -581,6 +595,7 @@ func TestCommandSide_ChangeLoginPolicy(t *testing.T) { AllowUsernamePassword: false, AllowExternalIDP: false, ForceMFA: false, + ForceMFALocalOnly: false, IgnoreUnknownUsernames: false, AllowDomainDiscovery: false, DisableLoginWithEmail: false, @@ -686,6 +701,7 @@ func TestCommandSide_RemoveLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -829,6 +845,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -873,6 +890,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -937,6 +955,7 @@ func TestCommandSide_AddIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -1104,6 +1123,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -1148,6 +1168,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -1204,6 +1225,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -1267,6 +1289,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, @@ -1338,6 +1361,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, "", time.Hour*1, diff --git a/internal/command/phone.go b/internal/command/phone.go index 30cabb6fc..7f550ceea 100644 --- a/internal/command/phone.go +++ b/internal/command/phone.go @@ -13,6 +13,6 @@ type Phone struct { Verified bool } -func newPhoneCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCodeWithExpiry, error) { - return newCryptoCodeWithExpiry(ctx, filter, domain.SecretGeneratorTypeVerifyPhoneCode, alg) +func (c *Commands) newPhoneCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) { + return c.newCode(ctx, filter, domain.SecretGeneratorTypeVerifyPhoneCode, alg) } diff --git a/internal/command/policy_login_model.go b/internal/command/policy_login_model.go index 50ece0f2f..732c2a16c 100644 --- a/internal/command/policy_login_model.go +++ b/internal/command/policy_login_model.go @@ -15,6 +15,7 @@ type LoginPolicyWriteModel struct { AllowRegister bool AllowExternalIDP bool ForceMFA bool + ForceMFALocalOnly bool HidePasswordReset bool IgnoreUnknownUsernames bool AllowDomainDiscovery bool @@ -38,6 +39,7 @@ func (wm *LoginPolicyWriteModel) Reduce() error { wm.AllowUserNamePassword = e.AllowUserNamePassword wm.AllowExternalIDP = e.AllowExternalIDP wm.ForceMFA = e.ForceMFA + wm.ForceMFALocalOnly = e.ForceMFALocalOnly wm.PasswordlessType = e.PasswordlessType wm.HidePasswordReset = e.HidePasswordReset wm.IgnoreUnknownUsernames = e.IgnoreUnknownUsernames @@ -64,6 +66,9 @@ func (wm *LoginPolicyWriteModel) Reduce() error { if e.ForceMFA != nil { wm.ForceMFA = *e.ForceMFA } + if e.ForceMFALocalOnly != nil { + wm.ForceMFALocalOnly = *e.ForceMFALocalOnly + } if e.HidePasswordReset != nil { wm.HidePasswordReset = *e.HidePasswordReset } diff --git a/internal/command/project_application.go b/internal/command/project_application.go index dfab28483..3929be9e7 100644 --- a/internal/command/project_application.go +++ b/internal/command/project_application.go @@ -16,8 +16,8 @@ type AddApp struct { Name string } -func newAppClientSecret(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.HashAlgorithm) (value *crypto.CryptoValue, plain string, err error) { - return newCryptoCodeWithPlain(ctx, filter, domain.SecretGeneratorTypeAppSecret, alg) +func (c *Commands) newAppClientSecret(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.HashAlgorithm) (*CryptoCode, error) { + return c.newCode(ctx, filter, domain.SecretGeneratorTypeAppSecret, alg) } func (c *Commands) ChangeApplication(ctx context.Context, projectID string, appChange domain.Application, resourceOwner string) (*domain.ObjectDetails, error) { diff --git a/internal/command/project_application_api.go b/internal/command/project_application_api.go index 7354e5f99..16ff044db 100644 --- a/internal/command/project_application_api.go +++ b/internal/command/project_application_api.go @@ -44,10 +44,11 @@ func (c *Commands) AddAPIAppCommand(app *addAPIApp, clientSecretAlg crypto.HashA } if app.AuthMethodType == domain.APIAuthMethodTypeBasic { - app.ClientSecret, app.ClientSecretPlain, err = newAppClientSecret(ctx, filter, clientSecretAlg) + code, err := c.newAppClientSecret(ctx, filter, clientSecretAlg) if err != nil { return nil, err } + app.ClientSecret, app.ClientSecretPlain = code.Crypted, code.Plain } return []eventstore.Command{ @@ -243,7 +244,7 @@ func (c *Commands) VerifyAPIClientSecret(ctx context.Context, projectID, appID, projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel) ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") - err = crypto.CompareHash(app.ClientSecret, []byte(secret), c.userPasswordAlg) + err = crypto.CompareHash(app.ClientSecret, []byte(secret), c.codeAlg) spanPasswordComparison.EndWithError(err) if err == nil { _, err = c.eventstore.Push(ctx, project_repo.NewAPIConfigSecretCheckSucceededEvent(ctx, projectAgg, app.AppID)) diff --git a/internal/command/project_application_oidc.go b/internal/command/project_application_oidc.go index 44efd279a..2d14ecf3a 100644 --- a/internal/command/project_application_oidc.go +++ b/internal/command/project_application_oidc.go @@ -77,10 +77,11 @@ func (c *Commands) AddOIDCAppCommand(app *addOIDCApp, clientSecretAlg crypto.Has } if app.AuthMethodType == domain.OIDCAuthMethodTypeBasic || app.AuthMethodType == domain.OIDCAuthMethodTypePost { - app.ClientSecret, app.ClientSecretPlain, err = newAppClientSecret(ctx, filter, clientSecretAlg) + code, err := c.newAppClientSecret(ctx, filter, clientSecretAlg) if err != nil { return nil, err } + app.ClientSecret, app.ClientSecretPlain = code.Crypted, code.Plain } return []eventstore.Command{ @@ -325,7 +326,7 @@ func (c *Commands) VerifyOIDCClientSecret(ctx context.Context, projectID, appID, projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel) ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") - err = crypto.CompareHash(app.ClientSecret, []byte(secret), c.userPasswordAlg) + err = crypto.CompareHash(app.ClientSecret, []byte(secret), c.codeAlg) spanPasswordComparison.EndWithError(err) if err == nil { _, err = c.eventstore.Push(ctx, project_repo.NewOIDCConfigSecretCheckSucceededEvent(ctx, projectAgg, app.AppID)) diff --git a/internal/command/quota_report.go b/internal/command/quota_report.go index b18b9e9b5..19855452e 100644 --- a/internal/command/quota_report.go +++ b/internal/command/quota_report.go @@ -7,8 +7,8 @@ import ( "github.com/zitadel/zitadel/internal/repository/quota" ) -// ReportUsage calls notification hooks and emits the notified events -func (c *Commands) ReportUsage(ctx context.Context, dueNotifications []*quota.NotificationDueEvent) error { +// ReportQuotaUsage writes a slice of *quota.NotificationDueEvent directly to the eventstore +func (c *Commands) ReportQuotaUsage(ctx context.Context, dueNotifications []*quota.NotificationDueEvent) error { cmds := make([]eventstore.Command, len(dueNotifications)) for idx, notification := range dueNotifications { cmds[idx] = notification diff --git a/internal/command/session.go b/internal/command/session.go index fb1dd42d0..86e249822 100644 --- a/internal/command/session.go +++ b/internal/command/session.go @@ -1,6 +1,7 @@ package command import ( + "bytes" "context" "encoding/base64" "fmt" @@ -13,30 +14,34 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/repository/session" + "github.com/zitadel/zitadel/internal/repository/user" + usr_repo "github.com/zitadel/zitadel/internal/repository/user" "github.com/zitadel/zitadel/internal/telemetry/tracing" ) type SessionCommand func(ctx context.Context, cmd *SessionCommands) error type SessionCommands struct { - cmds []SessionCommand + sessionCommands []SessionCommand sessionWriteModel *SessionWriteModel passwordWriteModel *HumanPasswordWriteModel intentWriteModel *IDPIntentWriteModel eventstore *eventstore.Eventstore - userPasswordAlg crypto.HashAlgorithm - intentAlg crypto.EncryptionAlgorithm - createToken func(sessionID string) (id string, token string, err error) - now func() time.Time + eventCommands []eventstore.Command + + hasher *crypto.PasswordHasher + intentAlg crypto.EncryptionAlgorithm + createToken func(sessionID string) (id string, token string, err error) + now func() time.Time } func (c *Commands) NewSessionCommands(cmds []SessionCommand, session *SessionWriteModel) *SessionCommands { return &SessionCommands{ - cmds: cmds, + sessionCommands: cmds, sessionWriteModel: session, eventstore: c.eventstore, - userPasswordAlg: c.userPasswordAlg, + hasher: c.userPasswordHasher, intentAlg: c.idpConfigEncryption, createToken: c.sessionTokenCreator, now: time.Now, @@ -49,7 +54,7 @@ func CheckUser(id string) SessionCommand { if cmd.sessionWriteModel.UserID != "" && id != "" && cmd.sessionWriteModel.UserID != id { return caos_errs.ThrowInvalidArgument(nil, "", "user change not possible") } - return cmd.sessionWriteModel.UserChecked(ctx, id, cmd.now()) + return cmd.UserChecked(ctx, id, cmd.now()) } } @@ -68,17 +73,21 @@ func CheckPassword(password string) SessionCommand { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Df4b3", "Errors.User.NotFound") } - if cmd.passwordWriteModel.Secret == nil { + if cmd.passwordWriteModel.EncodedHash == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-WEf3t", "Errors.User.Password.NotSet") } - ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") - err = crypto.CompareHash(cmd.passwordWriteModel.Secret, []byte(password), cmd.userPasswordAlg) + ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify") + updated, err := cmd.hasher.Verify(cmd.passwordWriteModel.EncodedHash, password) spanPasswordComparison.EndWithError(err) if err != nil { //TODO: maybe we want to reset the session in the future https://github.com/zitadel/zitadel/issues/5807 return caos_errs.ThrowInvalidArgument(err, "COMMAND-SAF3g", "Errors.User.Password.Invalid") } - cmd.sessionWriteModel.PasswordChecked(ctx, cmd.now()) + if updated != "" { + cmd.eventCommands = append(cmd.eventCommands, user.NewHumanPasswordHashUpdatedEvent(ctx, UserAggregateFromWriteModel(&cmd.passwordWriteModel.WriteModel), updated)) + } + + cmd.PasswordChecked(ctx, cmd.now()) return nil } } @@ -114,14 +123,14 @@ func CheckIntent(intentID, token string) SessionCommand { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-O8xk3w", "Errors.Intent.OtherUser") } } - cmd.sessionWriteModel.IntentChecked(ctx, cmd.now()) + cmd.IntentChecked(ctx, cmd.now()) return nil } } // Exec will execute the commands specified and returns an error on the first occurrence func (s *SessionCommands) Exec(ctx context.Context) error { - for _, cmd := range s.cmds { + for _, cmd := range s.sessionCommands { if err := cmd(ctx, s); err != nil { return err } @@ -129,6 +138,66 @@ func (s *SessionCommands) Exec(ctx context.Context) error { return nil } +func (s *SessionCommands) Start(ctx context.Context, domain string) { + s.eventCommands = append(s.eventCommands, session.NewAddedEvent(ctx, s.sessionWriteModel.aggregate, domain)) + // set the domain so checks can use it + s.sessionWriteModel.Domain = domain +} + +func (s *SessionCommands) UserChecked(ctx context.Context, userID string, checkedAt time.Time) error { + s.eventCommands = append(s.eventCommands, session.NewUserCheckedEvent(ctx, s.sessionWriteModel.aggregate, userID, checkedAt)) + // set the userID so other checks can use it + s.sessionWriteModel.UserID = userID + return nil +} + +func (s *SessionCommands) PasswordChecked(ctx context.Context, checkedAt time.Time) { + s.eventCommands = append(s.eventCommands, session.NewPasswordCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt)) +} + +func (s *SessionCommands) IntentChecked(ctx context.Context, checkedAt time.Time) { + s.eventCommands = append(s.eventCommands, session.NewIntentCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt)) +} + +func (s *SessionCommands) PasskeyChallenged(ctx context.Context, challenge string, allowedCrentialIDs [][]byte, userVerification domain.UserVerificationRequirement) { + s.eventCommands = append(s.eventCommands, session.NewPasskeyChallengedEvent(ctx, s.sessionWriteModel.aggregate, challenge, allowedCrentialIDs, userVerification)) +} + +func (s *SessionCommands) PasskeyChecked(ctx context.Context, checkedAt time.Time, tokenID string, signCount uint32) { + s.eventCommands = append(s.eventCommands, + session.NewPasskeyCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt), + usr_repo.NewHumanPasswordlessSignCountChangedEvent(ctx, s.sessionWriteModel.aggregate, tokenID, signCount), + ) +} + +func (s *SessionCommands) SetToken(ctx context.Context, tokenID string) { + s.eventCommands = append(s.eventCommands, session.NewTokenSetEvent(ctx, s.sessionWriteModel.aggregate, tokenID)) +} + +func (s *SessionCommands) ChangeMetadata(ctx context.Context, metadata map[string][]byte) { + var changed bool + for key, value := range metadata { + currentValue, exists := s.sessionWriteModel.Metadata[key] + + if len(value) != 0 { + // if a value is provided, and it's not equal, change it + if !bytes.Equal(currentValue, value) { + s.sessionWriteModel.Metadata[key] = value + changed = true + } + } else { + // if there's no / an empty value, we only need to remove it on existing entries + if exists { + delete(s.sessionWriteModel.Metadata, key) + changed = true + } + } + } + if changed { + s.eventCommands = append(s.eventCommands, session.NewMetadataSetEvent(ctx, s.sessionWriteModel.aggregate, s.sessionWriteModel.Metadata)) + } +} + func (s *SessionCommands) gethumanWriteModel(ctx context.Context) (*HumanWriteModel, error) { if s.sessionWriteModel.UserID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eeR2e", "Errors.User.UserIDMissing") @@ -145,7 +214,7 @@ func (s *SessionCommands) gethumanWriteModel(ctx context.Context) (*HumanWriteMo } func (s *SessionCommands) commands(ctx context.Context) (string, []eventstore.Command, error) { - if len(s.sessionWriteModel.commands) == 0 { + if len(s.eventCommands) == 0 { return "", nil, nil } @@ -153,8 +222,8 @@ func (s *SessionCommands) commands(ctx context.Context) (string, []eventstore.Co if err != nil { return "", nil, err } - s.sessionWriteModel.SetToken(ctx, tokenID) - return token, s.sessionWriteModel.commands, nil + s.SetToken(ctx, tokenID) + return token, s.eventCommands, nil } func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, sessionDomain string, metadata map[string][]byte) (set *SessionChanged, err error) { @@ -167,8 +236,8 @@ func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, ses if err != nil { return nil, err } - sessionWriteModel.Start(ctx, sessionDomain) cmd := c.NewSessionCommands(cmds, sessionWriteModel) + cmd.Start(ctx, sessionDomain) return c.updateSession(ctx, cmd, metadata) } @@ -185,13 +254,23 @@ func (c *Commands) UpdateSession(ctx context.Context, sessionID, sessionToken st return c.updateSession(ctx, cmd, metadata) } -func (c *Commands) TerminateSession(ctx context.Context, sessionID, sessionToken string) (*domain.ObjectDetails, error) { +func (c *Commands) TerminateSession(ctx context.Context, sessionID string, sessionToken string) (*domain.ObjectDetails, error) { + return c.terminateSession(ctx, sessionID, sessionToken, true) +} + +func (c *Commands) TerminateSessionWithoutTokenCheck(ctx context.Context, sessionID string) (*domain.ObjectDetails, error) { + return c.terminateSession(ctx, sessionID, "", false) +} + +func (c *Commands) terminateSession(ctx context.Context, sessionID, sessionToken string, mustCheckToken bool) (*domain.ObjectDetails, error) { sessionWriteModel := NewSessionWriteModel(sessionID, "") if err := c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel); err != nil { return nil, err } - if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionDelete); err != nil { - return nil, err + if mustCheckToken { + if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionDelete); err != nil { + return nil, err + } } if sessionWriteModel.State != domain.SessionStateActive { return writeModelToObjectDetails(&sessionWriteModel.WriteModel), nil @@ -217,7 +296,7 @@ func (c *Commands) updateSession(ctx context.Context, checks *SessionCommands, m // TODO: how to handle failed checks (e.g. pw wrong) https://github.com/zitadel/zitadel/issues/5807 return nil, err } - checks.sessionWriteModel.ChangeMetadata(ctx, metadata) + checks.ChangeMetadata(ctx, metadata) sessionToken, cmds, err := checks.commands(ctx) if err != nil { return nil, err diff --git a/internal/command/session_model.go b/internal/command/session_model.go index aed542697..dce787ff7 100644 --- a/internal/command/session_model.go +++ b/internal/command/session_model.go @@ -1,15 +1,12 @@ package command import ( - "bytes" - "context" "time" "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/session" - usr_repo "github.com/zitadel/zitadel/internal/repository/user" ) type PasskeyChallengeModel struct { @@ -48,7 +45,6 @@ type SessionWriteModel struct { PasskeyChallenge *PasskeyChallengeModel - commands []eventstore.Command aggregate *eventstore.Aggregate } @@ -151,62 +147,42 @@ func (wm *SessionWriteModel) reduceTerminate() { wm.State = domain.SessionStateTerminated } -func (wm *SessionWriteModel) Start(ctx context.Context, domain string) { - wm.commands = append(wm.commands, session.NewAddedEvent(ctx, wm.aggregate, domain)) - // set the domain so checks can use it - wm.Domain = domain -} - -func (wm *SessionWriteModel) UserChecked(ctx context.Context, userID string, checkedAt time.Time) error { - wm.commands = append(wm.commands, session.NewUserCheckedEvent(ctx, wm.aggregate, userID, checkedAt)) - // set the userID so other checks can use it - wm.UserID = userID - return nil -} - -func (wm *SessionWriteModel) PasswordChecked(ctx context.Context, checkedAt time.Time) { - wm.commands = append(wm.commands, session.NewPasswordCheckedEvent(ctx, wm.aggregate, checkedAt)) -} - -func (wm *SessionWriteModel) IntentChecked(ctx context.Context, checkedAt time.Time) { - wm.commands = append(wm.commands, session.NewIntentCheckedEvent(ctx, wm.aggregate, checkedAt)) -} - -func (wm *SessionWriteModel) PasskeyChallenged(ctx context.Context, challenge string, allowedCrentialIDs [][]byte, userVerification domain.UserVerificationRequirement) { - wm.commands = append(wm.commands, session.NewPasskeyChallengedEvent(ctx, wm.aggregate, challenge, allowedCrentialIDs, userVerification)) -} - -func (wm *SessionWriteModel) PasskeyChecked(ctx context.Context, checkedAt time.Time, tokenID string, signCount uint32) { - wm.commands = append(wm.commands, - session.NewPasskeyCheckedEvent(ctx, wm.aggregate, checkedAt), - usr_repo.NewHumanPasswordlessSignCountChangedEvent(ctx, wm.aggregate, tokenID, signCount), - ) -} - -func (wm *SessionWriteModel) SetToken(ctx context.Context, tokenID string) { - wm.commands = append(wm.commands, session.NewTokenSetEvent(ctx, wm.aggregate, tokenID)) -} - -func (wm *SessionWriteModel) ChangeMetadata(ctx context.Context, metadata map[string][]byte) { - var changed bool - for key, value := range metadata { - currentValue, exists := wm.Metadata[key] - - if len(value) != 0 { - // if a value is provided, and it's not equal, change it - if !bytes.Equal(currentValue, value) { - wm.Metadata[key] = value - changed = true - } - } else { - // if there's no / an empty value, we only need to remove it on existing entries - if exists { - delete(wm.Metadata, key) - changed = true - } +// AuthenticationTime returns the time the user authenticated using the latest time of all checks +func (wm *SessionWriteModel) AuthenticationTime() time.Time { + var authTime time.Time + for _, check := range []time.Time{ + wm.PasswordCheckedAt, + wm.PasskeyCheckedAt, + wm.IntentCheckedAt, + // TODO: add U2F and OTP check https://github.com/zitadel/zitadel/issues/5477 + } { + if check.After(authTime) { + authTime = check } } - if changed { - wm.commands = append(wm.commands, session.NewMetadataSetEvent(ctx, wm.aggregate, wm.Metadata)) + return authTime +} + +// AuthMethodTypes returns a list of UserAuthMethodTypes based on succeeded checks +func (wm *SessionWriteModel) AuthMethodTypes() []domain.UserAuthMethodType { + types := make([]domain.UserAuthMethodType, 0, domain.UserAuthMethodTypeIDP) + if !wm.PasswordCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypePassword) } + if !wm.PasskeyCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypePasswordless) + } + if !wm.IntentCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeIDP) + } + // TODO: add checks with https://github.com/zitadel/zitadel/issues/5477 + /* + if !wm.TOTPCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeOTP) + } + if !wm.U2FCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeU2F) + } + */ + return types } diff --git a/internal/command/session_passkey.go b/internal/command/session_passkey.go index 6de850b23..6ef3fccb2 100644 --- a/internal/command/session_passkey.go +++ b/internal/command/session_passkey.go @@ -51,7 +51,7 @@ func (c *Commands) CreatePasskeyChallenge(userVerification domain.UserVerificati return caos_errs.ThrowInternal(err, "COMMAND-Yah6A", "Errors.Internal") } - cmd.sessionWriteModel.PasskeyChallenged(ctx, webAuthNLogin.Challenge, webAuthNLogin.AllowedCredentialIDs, webAuthNLogin.UserVerification) + cmd.PasskeyChallenged(ctx, webAuthNLogin.Challenge, webAuthNLogin.AllowedCredentialIDs, webAuthNLogin.UserVerification) return nil } } @@ -78,7 +78,7 @@ func (c *Commands) CheckPasskey(credentialAssertionData json.Marshaler) SessionC if token == nil { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Aej7i", "Errors.User.WebAuthN.NotFound") } - cmd.sessionWriteModel.PasskeyChecked(ctx, cmd.now(), token.WebAuthNTokenID, signCount) + cmd.PasskeyChecked(ctx, cmd.now(), token.WebAuthNTokenID, signCount) return nil } } diff --git a/internal/command/session_test.go b/internal/command/session_test.go index 92d19ac24..2eee78cc0 100644 --- a/internal/command/session_test.go +++ b/internal/command/session_test.go @@ -140,7 +140,6 @@ func TestSessionCommands_getHumanWriteModel(t *testing.T) { func TestCommands_CreateSession(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore idGenerator id.Generator tokenCreator func(sessionID string) (string, string, error) } @@ -158,6 +157,7 @@ func TestCommands_CreateSession(t *testing.T) { name string fields fields args args + expect []expect res res }{ { @@ -168,6 +168,7 @@ func TestCommands_CreateSession(t *testing.T) { args{ ctx: context.Background(), }, + []expect{}, res{ err: caos_errs.ThrowInternal(nil, "id", "generator failed"), }, @@ -176,13 +177,13 @@ func TestCommands_CreateSession(t *testing.T) { "eventstore failed", fields{ idGenerator: mock.NewIDGeneratorExpectIDs(t, "sessionID"), - eventstore: eventstoreExpect(t, - expectFilterError(caos_errs.ThrowInternal(nil, "id", "filter failed")), - ), }, args{ ctx: context.Background(), }, + []expect{ + expectFilterError(caos_errs.ThrowInternal(nil, "id", "filter failed")), + }, res{ err: caos_errs.ThrowInternal(nil, "id", "filter failed"), }, @@ -191,17 +192,6 @@ func TestCommands_CreateSession(t *testing.T) { "empty session", fields{ idGenerator: mock.NewIDGeneratorExpectIDs(t, "sessionID"), - eventstore: eventstoreExpect(t, - expectFilter(), - expectPush( - eventPusherToEvents( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, ""), - session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, - "tokenID", - ), - ), - ), - ), tokenCreator: func(sessionID string) (string, string, error) { return "tokenID", "token", @@ -211,6 +201,17 @@ func TestCommands_CreateSession(t *testing.T) { args{ ctx: authz.NewMockContext("", "org1", ""), }, + []expect{ + expectFilter(), + expectPush( + eventPusherToEvents( + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, ""), + session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, + "tokenID", + ), + ), + ), + }, res{ want: &SessionChanged{ ObjectDetails: &domain.ObjectDetails{ResourceOwner: "org1"}, @@ -223,17 +224,6 @@ func TestCommands_CreateSession(t *testing.T) { "empty session with domain", fields{ idGenerator: mock.NewIDGeneratorExpectIDs(t, "sessionID"), - eventstore: eventstoreExpect(t, - expectFilter(), - expectPush( - eventPusherToEvents( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), - session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, - "tokenID", - ), - ), - ), - ), tokenCreator: func(sessionID string) (string, string, error) { return "tokenID", "token", @@ -244,6 +234,17 @@ func TestCommands_CreateSession(t *testing.T) { ctx: authz.NewMockContext("", "org1", ""), domain: "domain.tld", }, + []expect{ + expectFilter(), + expectPush( + eventPusherToEvents( + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), + session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, + "tokenID", + ), + ), + ), + }, res{ want: &SessionChanged{ ObjectDetails: &domain.ObjectDetails{ResourceOwner: "org1"}, @@ -257,7 +258,7 @@ func TestCommands_CreateSession(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: eventstoreExpect(t, tt.expect...), idGenerator: tt.fields.idGenerator, sessionTokenCreator: tt.fields.tokenCreator, } @@ -432,7 +433,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{ + sessionCommands: []SessionCommand{ func(ctx context.Context, cmd *SessionCommands) error { return caos_errs.ThrowInternal(nil, "id", "check failed") }, @@ -452,7 +453,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{}, + sessionCommands: []SessionCommand{}, }, }, res{ @@ -487,7 +488,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{ + sessionCommands: []SessionCommand{ CheckUser("userID"), CheckPassword("password"), }, @@ -499,12 +500,7 @@ func TestCommands_updateSession(t *testing.T) { ), eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, false, ""), + "$plain$x$password", false, ""), ), ), ), @@ -513,7 +509,7 @@ func TestCommands_updateSession(t *testing.T) { "token", nil }, - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + hasher: mockPasswordHasher("x"), now: func() time.Time { return testNow }, @@ -541,7 +537,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{ + sessionCommands: []SessionCommand{ CheckUser("userID"), CheckIntent("intent", "aW50ZW50"), }, @@ -580,7 +576,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{ + sessionCommands: []SessionCommand{ CheckUser("userID"), CheckIntent("intent", "aW50ZW50"), }, @@ -629,7 +625,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{ + sessionCommands: []SessionCommand{ CheckUser("userID"), CheckIntent("intent2", "aW50ZW50"), }, @@ -674,7 +670,7 @@ func TestCommands_updateSession(t *testing.T) { ctx: context.Background(), checks: &SessionCommands{ sessionWriteModel: NewSessionWriteModel("sessionID", "org1"), - cmds: []SessionCommand{ + sessionCommands: []SessionCommand{ CheckUser("userID"), CheckIntent("intent", "aW50ZW50"), }, diff --git a/internal/command/system_model.go b/internal/command/system_model.go index 40847cfab..6637013d5 100644 --- a/internal/command/system_model.go +++ b/internal/command/system_model.go @@ -181,8 +181,5 @@ func (wm *SystemConfigWriteModel) changeConfig(validation *SystemConfigChangesVa } func (wm *SystemConfigWriteModel) changeURIs(validation *SystemConfigChangesValidation, inst *systemConfigChangesInstanceModel, commands *Commands, domain string) { - if commands.checkUpdateConsoleRedirectURIs(domain, inst.RedirectUris, inst.PostLogoutRedirectUris) { - return - } validation.Validations = append(validation.Validations, commands.prepareUpdateConsoleRedirectURIs(domain)) } diff --git a/internal/command/user.go b/internal/command/user.go index 34ba7c521..77b9acbcc 100644 --- a/internal/command/user.go +++ b/internal/command/user.go @@ -439,8 +439,8 @@ func ExistsUser(ctx context.Context, filter preparation.FilterToQueryReducer, id return exists, nil } -func newUserInitCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCodeWithExpiry, error) { - return newCryptoCodeWithExpiry(ctx, filter, domain.SecretGeneratorTypeInitCode, alg) +func (c *Commands) newUserInitCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) { + return c.newCode(ctx, filter, domain.SecretGeneratorTypeInitCode, alg) } func userWriteModelByID(ctx context.Context, filter preparation.FilterToQueryReducer, userID, resourceOwner string) (*UserWriteModel, error) { diff --git a/internal/command/user_human.go b/internal/command/user_human.go index 061dc2232..1bbaec3ca 100644 --- a/internal/command/user_human.go +++ b/internal/command/user_human.go @@ -49,8 +49,8 @@ type AddHuman struct { Phone Phone // Password is optional Password string - // BcryptedPassword is optional - BcryptedPassword string + // EncodedPasswordHash is optional + EncodedPasswordHash string // PasswordChangeRequired is used if the `Password`-field is set PasswordChangeRequired bool Passwordless bool @@ -74,7 +74,7 @@ type AddLink struct { IDPExternalID string } -func (h *AddHuman) Validate() (err error) { +func (h *AddHuman) Validate(hasher *crypto.PasswordHasher) (err error) { if err := h.Email.Validate(); err != nil { return err } @@ -101,6 +101,11 @@ func (h *AddHuman) Validate() (err error) { return err } } + if h.EncodedPasswordHash != "" { + if !hasher.EncodingSupported(h.EncodedPasswordHash) { + return errors.ThrowInvalidArgument(nil, "USER-JDk4t", "Errors.User.Password.NotSupported") + } + } return nil } @@ -127,7 +132,7 @@ func (c *Commands) AddHuman(ctx context.Context, resourceOwner string, human *Ad c.AddHumanCommand( human, resourceOwner, - c.userPasswordAlg, + c.userPasswordHasher, c.userEncryption, allowInitMail, )) @@ -151,12 +156,13 @@ func (c *Commands) AddHuman(ctx context.Context, resourceOwner string, human *Ad type humanCreationCommand interface { eventstore.Command AddPhoneData(phoneNumber domain.PhoneNumber) - AddPasswordData(secret *crypto.CryptoValue, changeRequired bool) + AddPasswordData(encoded string, changeRequired bool) } -func (c *Commands) AddHumanCommand(human *AddHuman, orgID string, passwordAlg crypto.HashAlgorithm, codeAlg crypto.EncryptionAlgorithm, allowInitMail bool) preparation.Validation { +//nolint:gocognit +func (c *Commands) AddHumanCommand(human *AddHuman, orgID string, hasher *crypto.PasswordHasher, codeAlg crypto.EncryptionAlgorithm, allowInitMail bool) preparation.Validation { return func() (_ preparation.CreateCommands, err error) { - if err := human.Validate(); err != nil { + if err := human.Validate(hasher); err != nil { return nil, err } @@ -210,7 +216,7 @@ func (c *Commands) AddHumanCommand(human *AddHuman, orgID string, passwordAlg cr createCmd.AddPhoneData(human.Phone.Number) } - if err := addHumanCommandPassword(ctx, filter, createCmd, human, passwordAlg); err != nil { + if err := addHumanCommandPassword(ctx, filter, createCmd, human, hasher); err != nil { return nil, err } @@ -258,7 +264,7 @@ func (c *Commands) addHumanCommandEmail(ctx context.Context, filter preparation. // email not verified or // user not registered and password set if allowInitMail && human.shouldAddInitCode() { - initCode, err := newUserInitCode(ctx, filter, codeAlg) + initCode, err := c.newUserInitCode(ctx, filter, codeAlg) if err != nil { return nil, err } @@ -292,7 +298,7 @@ func (c *Commands) addHumanCommandPhone(ctx context.Context, filter preparation. if human.Phone.Verified { return append(cmds, user.NewHumanPhoneVerifiedEvent(ctx, &a.Aggregate)), nil } - phoneCode, err := newPhoneCode(ctx, filter, codeAlg) + phoneCode, err := c.newPhoneCode(ctx, filter, codeAlg) if err != nil { return nil, err } @@ -316,13 +322,13 @@ func (c *Commands) addHumanCommandCheckID(ctx context.Context, filter preparatio return nil } -func addHumanCommandPassword(ctx context.Context, filter preparation.FilterToQueryReducer, createCmd humanCreationCommand, human *AddHuman, passwordAlg crypto.HashAlgorithm) (err error) { +func addHumanCommandPassword(ctx context.Context, filter preparation.FilterToQueryReducer, createCmd humanCreationCommand, human *AddHuman, hasher *crypto.PasswordHasher) (err error) { if human.Password != "" { if err = humanValidatePassword(ctx, filter, human.Password); err != nil { return err } - secret, err := crypto.Hash([]byte(human.Password), passwordAlg) + secret, err := hasher.Hash(human.Password) if err != nil { return err } @@ -330,8 +336,8 @@ func addHumanCommandPassword(ctx context.Context, filter preparation.FilterToQue return nil } - if human.BcryptedPassword != "" { - createCmd.AddPasswordData(crypto.FillHash([]byte(human.BcryptedPassword), passwordAlg), human.PasswordChangeRequired) + if human.EncodedPasswordHash != "" { + createCmd.AddPasswordData(human.EncodedPasswordHash, human.PasswordChangeRequired) } return nil } @@ -578,7 +584,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain. human.EnsureDisplayName() if human.Password != nil { - if err := human.HashPasswordIfExisting(pwPolicy, c.userPasswordAlg, human.Password.ChangeRequired); err != nil { + if err := human.HashPasswordIfExisting(pwPolicy, c.userPasswordHasher, human.Password.ChangeRequired); err != nil { return nil, nil, err } } @@ -677,10 +683,10 @@ func createAddHumanEvent(ctx context.Context, aggregate *eventstore.Aggregate, h human.StreetAddress) } if human.Password != nil { - addEvent.AddPasswordData(human.Password.SecretCrypto, human.Password.ChangeRequired) + addEvent.AddPasswordData(human.Password.EncodedSecret, human.Password.ChangeRequired) } - if human.HashedPassword != nil { - addEvent.AddPasswordData(human.HashedPassword.SecretCrypto, false) + if human.HashedPassword != "" { + addEvent.AddPasswordData(human.HashedPassword, false) } return addEvent } @@ -711,10 +717,10 @@ func createRegisterHumanEvent(ctx context.Context, aggregate *eventstore.Aggrega human.StreetAddress) } if human.Password != nil { - addEvent.AddPasswordData(human.Password.SecretCrypto, human.Password.ChangeRequired) + addEvent.AddPasswordData(human.Password.EncodedSecret, human.Password.ChangeRequired) } - if human.HashedPassword != nil { - addEvent.AddPasswordData(human.HashedPassword.SecretCrypto, false) + if human.HashedPassword != "" { + addEvent.AddPasswordData(human.HashedPassword, false) } return addEvent } diff --git a/internal/command/user_human_init.go b/internal/command/user_human_init.go index 74deb4ced..5af8eb9a5 100644 --- a/internal/command/user_human_init.go +++ b/internal/command/user_human_init.go @@ -4,6 +4,7 @@ import ( "context" "github.com/zitadel/logging" + "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" @@ -49,7 +50,7 @@ func (c *Commands) ResendInitialMail(ctx context.Context, userID string, email d return writeModelToObjectDetails(&existingCode.WriteModel), nil } -func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwner, code, passwordString string, initCodeGenerator crypto.Generator) error { +func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwner, code, password string, initCodeGenerator crypto.Generator) error { if userID == "" { return caos_errs.ThrowInvalidArgument(nil, "COMMAND-mkM9f", "Errors.User.UserIDMissing") } @@ -72,26 +73,22 @@ func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwne logging.WithFields("userID", userAgg.ID).OnError(err).Error("NewHumanInitializedCheckFailedEvent push failed") return caos_errs.ThrowInvalidArgument(err, "COMMAND-11v6G", "Errors.User.Code.Invalid") } - events := []eventstore.Command{ + commands := []eventstore.Command{ user.NewHumanInitializedCheckSucceededEvent(ctx, userAgg), } if !existingCode.IsEmailVerified { - events = append(events, user.NewHumanEmailVerifiedEvent(ctx, userAgg)) + commands = append(commands, user.NewHumanEmailVerifiedEvent(ctx, userAgg)) } - if passwordString != "" { + if password != "" { passwordWriteModel := NewHumanPasswordWriteModel(userID, existingCode.ResourceOwner) passwordWriteModel.UserState = domain.UserStateActive - password := &domain.Password{ - SecretString: passwordString, - ChangeRequired: false, - } - passwordEvent, err := c.changePassword(ctx, "", password, userAgg, passwordWriteModel) + passwordCommand, err := c.setPasswordCommand(ctx, passwordWriteModel, password, false) if err != nil { return err } - events = append(events, passwordEvent) + commands = append(commands, passwordCommand) } - _, err = c.eventstore.Push(ctx, events...) + _, err = c.eventstore.Push(ctx, commands...) return err } diff --git a/internal/command/user_human_init_test.go b/internal/command/user_human_init_test.go index 838459bd2..69fce8366 100644 --- a/internal/command/user_human_init_test.go +++ b/internal/command/user_human_init_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "golang.org/x/text/language" @@ -305,8 +304,8 @@ func TestCommandSide_ResendInitialMail(t *testing.T) { func TestCommandSide_VerifyInitCode(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - userPasswordAlg crypto.HashAlgorithm + eventstore *eventstore.Eventstore + userPasswordHasher *crypto.PasswordHasher } type args struct { ctx context.Context @@ -584,18 +583,13 @@ func TestCommandSide_VerifyInitCode(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", false, "")), }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -615,8 +609,8 @@ func TestCommandSide_VerifyInitCode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: tt.fields.userPasswordAlg, + eventstore: tt.fields.eventstore, + userPasswordHasher: tt.fields.userPasswordHasher, } err := r.HumanVerifyInitCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.code, tt.args.password, tt.args.secretGenerator) if tt.res.err == nil { diff --git a/internal/command/user_human_otp_test.go b/internal/command/user_human_otp_test.go index e11f771e6..ae44489ae 100644 --- a/internal/command/user_human_otp_test.go +++ b/internal/command/user_human_otp_test.go @@ -528,7 +528,7 @@ func TestCommands_createHumanOTP(t *testing.T) { } func TestCommands_HumanCheckMFAOTPSetup(t *testing.T) { - ctx := authz.NewMockContext("inst1", "org1", "user1") + ctx := authz.NewMockContext("", "org1", "user1") cryptoAlg := crypto.CreateMockEncryptionAlg(gomock.NewController(t)) key, secret, err := domain.NewOTPKey("example.com", "user1", cryptoAlg) diff --git a/internal/command/user_human_password.go b/internal/command/user_human_password.go index 8d54727e2..0a2992a46 100644 --- a/internal/command/user_human_password.go +++ b/internal/command/user_human_password.go @@ -2,8 +2,10 @@ package command import ( "context" + "errors" "github.com/zitadel/logging" + "github.com/zitadel/passwap" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" @@ -13,80 +15,75 @@ import ( "github.com/zitadel/zitadel/internal/telemetry/tracing" ) -func (c *Commands) SetPassword(ctx context.Context, orgID, userID, passwordString string, oneTime bool) (objectDetails *domain.ObjectDetails, err error) { +func (c *Commands) SetPassword(ctx context.Context, orgID, userID, password string, oneTime bool) (objectDetails *domain.ObjectDetails, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M0fs", "Errors.IDMissing") } - existingPassword, err := c.passwordWriteModel(ctx, userID, orgID) + wm, err := c.passwordWriteModel(ctx, userID, orgID) if err != nil { return nil, err } - if !existingPassword.UserState.Exists() { + if !wm.UserState.Exists() { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3M0fs", "Errors.User.NotFound") } - if err = c.checkPermission(ctx, domain.PermissionUserWrite, existingPassword.ResourceOwner, userID); err != nil { + if err = c.checkPermission(ctx, domain.PermissionUserWrite, wm.ResourceOwner, userID); err != nil { return nil, err } - password := &domain.Password{ - SecretString: passwordString, - ChangeRequired: oneTime, - } - userAgg := UserAggregateFromWriteModel(&existingPassword.WriteModel) - passwordEvent, err := c.changePassword(ctx, "", password, userAgg, existingPassword) - if err != nil { - return nil, err - } - pushedEvents, err := c.eventstore.Push(ctx, passwordEvent) - if err != nil { - return nil, err - } - err = AppendAndReduce(existingPassword, pushedEvents...) - if err != nil { - return nil, err - } - return writeModelToObjectDetails(&existingPassword.WriteModel), nil + return c.setPassword(ctx, wm, password, oneTime) } -func (c *Commands) SetPasswordWithVerifyCode(ctx context.Context, orgID, userID, code, passwordString, userAgentID string) (objectDetails *domain.ObjectDetails, err error) { +func (c *Commands) SetPasswordWithVerifyCode(ctx context.Context, orgID, userID, code, password, userAgentID string) (objectDetails *domain.ObjectDetails, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M9fs", "Errors.IDMissing") } - if passwordString == "" { + if password == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Mf0sd", "Errors.User.Password.Empty") } - existingCode, err := c.passwordWriteModel(ctx, userID, orgID) + wm, err := c.passwordWriteModel(ctx, userID, orgID) if err != nil { return nil, err } - if existingCode.Code == nil || existingCode.UserState == domain.UserStateUnspecified || existingCode.UserState == domain.UserStateDeleted { + if wm.Code == nil || wm.UserState == domain.UserStateUnspecified || wm.UserState == domain.UserStateDeleted { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9fs", "Errors.User.Code.NotFound") } - err = crypto.VerifyCodeWithAlgorithm(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, c.userEncryption) + err = crypto.VerifyCodeWithAlgorithm(wm.CodeCreationDate, wm.CodeExpiry, wm.Code, code, c.userEncryption) if err != nil { return nil, err } - password := &domain.Password{ - SecretString: passwordString, - ChangeRequired: false, - } - userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel) - passwordEvent, err := c.changePassword(ctx, userAgentID, password, userAgg, existingCode) + return c.setPassword(ctx, wm, password, false) +} + +func (c *Commands) setPassword(ctx context.Context, wm *HumanPasswordWriteModel, password string, changeRequired bool) (objectDetails *domain.ObjectDetails, err error) { + command, err := c.setPasswordCommand(ctx, wm, password, changeRequired) if err != nil { return nil, err } - err = c.pushAppendAndReduce(ctx, existingCode, passwordEvent) + err = c.pushAppendAndReduce(ctx, wm, command) if err != nil { return nil, err } - return writeModelToObjectDetails(&existingCode.WriteModel), nil + return writeModelToObjectDetails(&wm.WriteModel), nil +} + +func (c *Commands) setPasswordCommand(ctx context.Context, wm *HumanPasswordWriteModel, password string, changeRequired bool) (_ eventstore.Command, err error) { + if err = c.canUpdatePassword(ctx, password, wm); err != nil { + return nil, err + } + ctx, span := tracing.NewNamedSpan(ctx, "passwap.Hash") + encoded, err := c.userPasswordHasher.Hash(password) + span.EndWithError(err) + if err = convertPasswapErr(err); err != nil { + return nil, err + } + return user.NewHumanPasswordChangedEvent(ctx, UserAggregateFromWriteModel(&wm.WriteModel), encoded, changeRequired, ""), nil } func (c *Commands) ChangePassword(ctx context.Context, orgID, userID, oldPassword, newPassword, userAgentID string) (objectDetails *domain.ObjectDetails, err error) { @@ -99,59 +96,50 @@ func (c *Commands) ChangePassword(ctx context.Context, orgID, userID, oldPasswor if oldPassword == "" || newPassword == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M0fs", "Errors.User.Password.Empty") } - existingPassword, err := c.passwordWriteModel(ctx, userID, orgID) + wm, err := c.passwordWriteModel(ctx, userID, orgID) if err != nil { return nil, err } - if existingPassword.Secret == nil { + if wm.EncodedHash == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Fds3s", "Errors.User.Password.Empty") } - ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") - err = crypto.CompareHash(existingPassword.Secret, []byte(oldPassword), c.userPasswordAlg) - spanPasswordComparison.EndWithError(err) - - if err != nil { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M0fs", "Errors.User.Password.Invalid") - } - password := &domain.Password{ - SecretString: newPassword, - ChangeRequired: false, + if err = c.canUpdatePassword(ctx, newPassword, wm); err != nil { + return nil, err } - userAgg := UserAggregateFromWriteModel(&existingPassword.WriteModel) - command, err := c.changePassword(ctx, userAgentID, password, userAgg, existingPassword) + ctx, spanPasswap := tracing.NewNamedSpan(ctx, "passwap.VerifyAndUpdate") + updated, err := c.userPasswordHasher.VerifyAndUpdate(wm.EncodedHash, oldPassword, newPassword) + spanPasswap.EndWithError(err) + if err = convertPasswapErr(err); err != nil { + return nil, err + } + err = c.pushAppendAndReduce(ctx, wm, + user.NewHumanPasswordChangedEvent(ctx, UserAggregateFromWriteModel(&wm.WriteModel), updated, false, userAgentID)) if err != nil { return nil, err } - pushedEvents, err := c.eventstore.Push(ctx, command) - if err != nil { - return nil, err - } - err = AppendAndReduce(existingPassword, pushedEvents...) - if err != nil { - return nil, err - } - return writeModelToObjectDetails(&existingPassword.WriteModel), nil + return writeModelToObjectDetails(&wm.WriteModel), nil } -func (c *Commands) changePassword(ctx context.Context, userAgentID string, password *domain.Password, userAgg *eventstore.Aggregate, existingPassword *HumanPasswordWriteModel) (event eventstore.Command, err error) { +func (c *Commands) canUpdatePassword(ctx context.Context, newPassword string, wm *HumanPasswordWriteModel) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - if existingPassword.UserState == domain.UserStateUnspecified || existingPassword.UserState == domain.UserStateDeleted { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-G8dh3", "Errors.User.Password.NotFound") + if wm.UserState == domain.UserStateUnspecified || wm.UserState == domain.UserStateDeleted { + return caos_errs.ThrowNotFound(nil, "COMMAND-G8dh3", "Errors.User.Password.NotFound") } - if existingPassword.UserState == domain.UserStateInitial { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-M9dse", "Errors.User.NotInitialised") + if wm.UserState == domain.UserStateInitial { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-M9dse", "Errors.User.NotInitialised") } - pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, userAgg.ResourceOwner) + policy, err := c.getOrgPasswordComplexityPolicy(ctx, wm.ResourceOwner) if err != nil { - return nil, err + return err } - if err := password.HashPasswordIfExisting(pwPolicy, c.userPasswordAlg); err != nil { - return nil, err + + if err := policy.Check(newPassword); err != nil { + return err } - return user.NewHumanPasswordChangedEvent(ctx, userAgg, password.SecretCrypto, password.ChangeRequired, userAgentID), nil + return nil } func (c *Commands) RequestSetPassword(ctx context.Context, userID, resourceOwner string, notifyType domain.NotificationType, passwordVerificationCode crypto.Generator) (objectDetails *domain.ObjectDetails, err error) { @@ -238,37 +226,44 @@ func (c *Commands) HumanCheckPassword(ctx context.Context, orgID, userID, passwo return caos_errs.ThrowPreconditionFailed(err, "COMMAND-Dft32", "Errors.Org.LoginPolicy.UsernamePasswordNotAllowed") } - existingPassword, err := c.passwordWriteModel(ctx, userID, orgID) + wm, err := c.passwordWriteModel(ctx, userID, orgID) if err != nil { return err } - if existingPassword.UserState == domain.UserStateUnspecified || existingPassword.UserState == domain.UserStateDeleted { + if wm.UserState == domain.UserStateUnspecified || wm.UserState == domain.UserStateDeleted { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3n77z", "Errors.User.NotFound") } - if existingPassword.Secret == nil { + if wm.EncodedHash == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3n77z", "Errors.User.Password.NotSet") } - userAgg := UserAggregateFromWriteModel(&existingPassword.WriteModel) - ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") - err = crypto.CompareHash(existingPassword.Secret, []byte(password), c.userPasswordAlg) + userAgg := UserAggregateFromWriteModel(&wm.WriteModel) + ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify") + updated, err := c.userPasswordHasher.Verify(wm.EncodedHash, password) spanPasswordComparison.EndWithError(err) + err = convertPasswapErr(err) + + commands := make([]eventstore.Command, 0, 2) if err == nil { - _, err = c.eventstore.Push(ctx, user.NewHumanPasswordCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + commands = append(commands, user.NewHumanPasswordCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + if updated != "" { + commands = append(commands, user.NewHumanPasswordHashUpdatedEvent(ctx, userAgg, updated)) + } + _, err = c.eventstore.Push(ctx, commands...) return err } - events := make([]eventstore.Command, 0) - events = append(events, user.NewHumanPasswordCheckFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + + commands = append(commands, user.NewHumanPasswordCheckFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) if lockoutPolicy != nil && lockoutPolicy.MaxPasswordAttempts > 0 { - if existingPassword.PasswordCheckFailedCount+1 >= lockoutPolicy.MaxPasswordAttempts { - events = append(events, user.NewUserLockedEvent(ctx, userAgg)) + if wm.PasswordCheckFailedCount+1 >= lockoutPolicy.MaxPasswordAttempts { + commands = append(commands, user.NewUserLockedEvent(ctx, userAgg)) } } - _, err = c.eventstore.Push(ctx, events...) - logging.Log("COMMAND-9fj7s").OnError(err).Error("error create password check failed event") - return caos_errs.ThrowInvalidArgument(nil, "COMMAND-452ad", "Errors.User.Password.Invalid") + _, pushErr := c.eventstore.Push(ctx, commands...) + logging.OnError(pushErr).Error("error create password check failed event") + return err } func (c *Commands) passwordWriteModel(ctx context.Context, userID, resourceOwner string) (writeModel *HumanPasswordWriteModel, err error) { @@ -282,3 +277,16 @@ func (c *Commands) passwordWriteModel(ctx context.Context, userID, resourceOwner } return writeModel, nil } + +func convertPasswapErr(err error) error { + if err == nil { + return nil + } + if errors.Is(err, passwap.ErrPasswordMismatch) { + return caos_errs.ThrowInvalidArgument(err, "COMMAND-3M0fs", "Errors.User.Password.Invalid") + } + if errors.Is(err, passwap.ErrPasswordNoChange) { + return caos_errs.ThrowPreconditionFailed(err, "COMMAND-Aesh5", "Errors.User.Password.NotChanged") + } + return caos_errs.ThrowInternal(err, "COMMAND-CahN2", "Errors.Internal") +} diff --git a/internal/command/user_human_password_model.go b/internal/command/user_human_password_model.go index 68513a853..c0ca58f58 100644 --- a/internal/command/user_human_password_model.go +++ b/internal/command/user_human_password_model.go @@ -13,7 +13,7 @@ import ( type HumanPasswordWriteModel struct { eventstore.WriteModel - Secret *crypto.CryptoValue + EncodedHash string SecretChangeRequired bool Code *crypto.CryptoValue @@ -37,11 +37,11 @@ func (wm *HumanPasswordWriteModel) Reduce() error { for _, event := range wm.Events { switch e := event.(type) { case *user.HumanAddedEvent: - wm.Secret = e.Secret + wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash) wm.SecretChangeRequired = e.ChangeRequired wm.UserState = domain.UserStateActive case *user.HumanRegisteredEvent: - wm.Secret = e.Secret + wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash) wm.SecretChangeRequired = e.ChangeRequired wm.UserState = domain.UserStateActive case *user.HumanInitialCodeAddedEvent: @@ -49,7 +49,7 @@ func (wm *HumanPasswordWriteModel) Reduce() error { case *user.HumanInitializedCheckSucceededEvent: wm.UserState = domain.UserStateActive case *user.HumanPasswordChangedEvent: - wm.Secret = e.Secret + wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash) wm.SecretChangeRequired = e.ChangeRequired wm.Code = nil wm.PasswordCheckFailedCount = 0 @@ -69,6 +69,8 @@ func (wm *HumanPasswordWriteModel) Reduce() error { wm.PasswordCheckFailedCount = 0 case *user.UserRemovedEvent: wm.UserState = domain.UserStateDeleted + case *user.HumanPasswordHashUpdatedEvent: + wm.EncodedHash = e.EncodedHash } } return wm.WriteModel.Reduce() @@ -98,7 +100,8 @@ func (wm *HumanPasswordWriteModel) Query() *eventstore.SearchQueryBuilder { user.UserV1PasswordCodeAddedType, user.UserV1EmailVerifiedType, user.UserV1PasswordCheckFailedType, - user.UserV1PasswordCheckSucceededType). + user.UserV1PasswordCheckSucceededType, + user.UserV1PasswordHashUpdatedType). Builder() if wm.ResourceOwner != "" { diff --git a/internal/command/user_human_password_test.go b/internal/command/user_human_password_test.go index 6eabda952..0a59b2ad3 100644 --- a/internal/command/user_human_password_test.go +++ b/internal/command/user_human_password_test.go @@ -3,11 +3,13 @@ package command import ( "context" "errors" + "io" "testing" "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "github.com/zitadel/passwap" "golang.org/x/text/language" "github.com/zitadel/zitadel/internal/crypto" @@ -21,9 +23,9 @@ import ( func TestCommandSide_SetOneTimePassword(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - userPasswordAlg crypto.HashAlgorithm - checkPermission domain.PermissionCheck + eventstore *eventstore.Eventstore + userPasswordHasher *crypto.PasswordHasher + checkPermission domain.PermissionCheck } type args struct { ctx context.Context @@ -101,8 +103,8 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { ), ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - checkPermission: newMockPermissionCheckNotAllowed(), + userPasswordHasher: mockPasswordHasher("x"), + checkPermission: newMockPermissionCheckNotAllowed(), }, args: args{ ctx: context.Background(), @@ -160,12 +162,7 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", true, "", ), @@ -173,8 +170,8 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - checkPermission: newMockPermissionCheckAllowed(), + userPasswordHasher: mockPasswordHasher("x"), + checkPermission: newMockPermissionCheckAllowed(), }, args: args{ ctx: context.Background(), @@ -232,12 +229,7 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", false, "", ), @@ -245,8 +237,8 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - checkPermission: newMockPermissionCheckAllowed(), + userPasswordHasher: mockPasswordHasher("x"), + checkPermission: newMockPermissionCheckAllowed(), }, args: args{ ctx: context.Background(), @@ -265,9 +257,9 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: tt.fields.userPasswordAlg, - checkPermission: tt.fields.checkPermission, + eventstore: tt.fields.eventstore, + userPasswordHasher: tt.fields.userPasswordHasher, + checkPermission: tt.fields.checkPermission, } got, err := r.SetPassword(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.password, tt.args.oneTime) if tt.res.err == nil { @@ -285,9 +277,9 @@ func TestCommandSide_SetOneTimePassword(t *testing.T) { func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - userEncryption crypto.EncryptionAlgorithm - userPasswordAlg crypto.HashAlgorithm + eventstore *eventstore.Eventstore + userEncryption crypto.EncryptionAlgorithm + userPasswordHasher *crypto.PasswordHasher } type args struct { ctx context.Context @@ -494,12 +486,7 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", false, "", ), @@ -507,8 +494,8 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) { }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: context.Background(), @@ -527,9 +514,9 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: tt.fields.userPasswordAlg, - userEncryption: tt.fields.userEncryption, + eventstore: tt.fields.eventstore, + userPasswordHasher: tt.fields.userPasswordHasher, + userEncryption: tt.fields.userEncryption, } got, err := r.SetPasswordWithVerifyCode(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.code, tt.args.password, tt.args.agentID) if tt.res.err == nil { @@ -547,8 +534,7 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) { func TestCommandSide_ChangePassword(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - userPasswordAlg crypto.HashAlgorithm + userPasswordHasher *crypto.PasswordHasher } type args struct { ctx context.Context @@ -566,67 +552,54 @@ func TestCommandSide_ChangePassword(t *testing.T) { name string fields fields args args + expect []expect res res }{ { - name: "userid missing, invalid argument error", - fields: fields{ - eventstore: eventstoreExpect( - t, - ), - }, + name: "userid missing, invalid argument error", + fields: fields{}, args: args{ ctx: context.Background(), oldPassword: "password", newPassword: "password1", resourceOwner: "org1", }, + expect: []expect{}, res: res{ err: caos_errs.IsErrorInvalidArgument, }, }, { - name: "old password missing, invalid argument error", - fields: fields{ - eventstore: eventstoreExpect( - t, - ), - }, + name: "old password missing, invalid argument error", + fields: fields{}, args: args{ ctx: context.Background(), userID: "user1", newPassword: "password1", resourceOwner: "org1", }, + expect: []expect{}, res: res{ err: caos_errs.IsErrorInvalidArgument, }, }, { - name: "new password missing, invalid argument error", - fields: fields{ - eventstore: eventstoreExpect( - t, - ), - }, + name: "new password missing, invalid argument error", + fields: fields{}, args: args{ ctx: context.Background(), userID: "user1", oldPassword: "password", resourceOwner: "org1", }, + expect: []expect{}, res: res{ err: caos_errs.IsErrorInvalidArgument, }, }, { - name: "user not existing, precondition error", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter(), - ), - }, + name: "user not existing, precondition error", + fields: fields{}, args: args{ ctx: context.Background(), userID: "user1", @@ -634,6 +607,9 @@ func TestCommandSide_ChangePassword(t *testing.T) { oldPassword: "password", newPassword: "password1", }, + expect: []expect{ + expectFilter(), + }, res: res{ err: caos_errs.IsPreconditionFailed, }, @@ -641,26 +617,7 @@ func TestCommandSide_ChangePassword(t *testing.T) { { name: "existing password empty, precondition error", fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - user.NewHumanAddedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - "username", - "firstname", - "lastname", - "nickname", - "displayname", - language.German, - domain.GenderUnspecified, - "email@test.ch", - true, - ), - ), - ), - ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -669,49 +626,32 @@ func TestCommandSide_ChangePassword(t *testing.T) { newPassword: "password1", resourceOwner: "org1", }, + expect: []expect{ + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "username", + "firstname", + "lastname", + "nickname", + "displayname", + language.German, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + ), + }, res: res{ err: caos_errs.IsPreconditionFailed, }, }, { - name: "password not matching, precondition error", + name: "password not matching, invalid argument error", fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - user.NewHumanAddedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - "username", - "firstname", - "lastname", - "nickname", - "displayname", - language.German, - domain.GenderUnspecified, - "email@test.ch", - true, - ), - ), - eventFromEventPusher( - user.NewHumanEmailVerifiedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - ), - ), - eventFromEventPusher( - user.NewHumanPasswordChangedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, - false, - "")), - ), - ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -720,6 +660,47 @@ func TestCommandSide_ChangePassword(t *testing.T) { newPassword: "password1", resourceOwner: "org1", }, + expect: []expect{ + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "username", + "firstname", + "lastname", + "nickname", + "displayname", + language.German, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusher( + user.NewHumanPasswordChangedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "$plain$x$password", + false, + "")), + ), + expectFilter( + eventFromEventPusher( + org.NewPasswordComplexityPolicyAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + 1, + false, + false, + false, + false, + ), + ), + ), + }, res: res{ err: caos_errs.IsErrorInvalidArgument, }, @@ -727,71 +708,7 @@ func TestCommandSide_ChangePassword(t *testing.T) { { name: "change password, ok", fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - user.NewHumanAddedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - "username", - "firstname", - "lastname", - "nickname", - "displayname", - language.German, - domain.GenderUnspecified, - "email@test.ch", - true, - ), - ), - eventFromEventPusher( - user.NewHumanEmailVerifiedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - ), - ), - eventFromEventPusher( - user.NewHumanPasswordChangedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, - false, - "")), - ), - expectFilter( - eventFromEventPusher( - org.NewPasswordComplexityPolicyAddedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - 1, - false, - false, - false, - false, - ), - ), - ), - expectPush( - []*repository.Event{ - eventFromEventPusher( - user.NewHumanPasswordChangedEvent(context.Background(), - &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password1"), - }, - false, - "", - ), - ), - }, - ), - ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -800,6 +717,59 @@ func TestCommandSide_ChangePassword(t *testing.T) { oldPassword: "password", newPassword: "password1", }, + expect: []expect{ + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "username", + "firstname", + "lastname", + "nickname", + "displayname", + language.German, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusher( + user.NewHumanPasswordChangedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "$plain$x$password", + false, + "")), + ), + expectFilter( + eventFromEventPusher( + org.NewPasswordComplexityPolicyAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + 1, + false, + false, + false, + false, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + user.NewHumanPasswordChangedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "$plain$x$password1", + false, + "", + ), + ), + }, + ), + }, res: res{ want: &domain.ObjectDetails{ ResourceOwner: "org1", @@ -810,8 +780,8 @@ func TestCommandSide_ChangePassword(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: tt.fields.userPasswordAlg, + eventstore: eventstoreExpect(t, tt.expect...), + userPasswordHasher: tt.fields.userPasswordHasher, } got, err := r.ChangePassword(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.oldPassword, tt.args.newPassword, tt.args.agentID) if tt.res.err == nil { @@ -1123,8 +1093,8 @@ func TestCommandSide_PasswordCodeSent(t *testing.T) { func TestCommandSide_CheckPassword(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - userPasswordAlg crypto.HashAlgorithm + eventstore *eventstore.Eventstore + userPasswordHasher *crypto.PasswordHasher } type args struct { ctx context.Context @@ -1212,6 +1182,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -1252,6 +1223,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -1293,6 +1265,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -1320,7 +1293,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { ), ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1350,6 +1323,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -1383,12 +1357,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", false, "")), ), @@ -1406,7 +1375,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1441,6 +1410,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -1474,12 +1444,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", false, "")), ), @@ -1502,7 +1467,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1539,6 +1504,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -1572,12 +1538,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { eventFromEventPusher( user.NewHumanPasswordChangedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, - &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, + "$plain$x$password", false, "")), ), @@ -1595,7 +1556,197 @@ func TestCommandSide_CheckPassword(t *testing.T) { }, ), ), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + userPasswordHasher: mockPasswordHasher("x"), + }, + args: args{ + ctx: context.Background(), + userID: "user1", + resourceOwner: "org1", + password: "password", + authReq: &domain.AuthRequest{ + ID: "request1", + AgentID: "agent1", + }, + }, + res: res{}, + }, + { + name: "check password, ok, updated hash", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewLoginPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + domain.PasswordlessTypeNotAllowed, + "", + time.Hour*1, + time.Hour*2, + time.Hour*3, + time.Hour*4, + time.Hour*5, + ), + ), + ), + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "username", + "firstname", + "lastname", + "nickname", + "displayname", + language.German, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusher( + user.NewHumanPasswordChangedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "$plain$v$password", + false, + "")), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + user.NewHumanPasswordCheckSucceededEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "request1", + UserAgentID: "agent1", + }, + ), + ), + eventFromEventPusher( + user.NewHumanPasswordHashUpdatedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "$plain$x$password", + ), + ), + }, + ), + ), + userPasswordHasher: mockPasswordHasher("x"), + }, + args: args{ + ctx: context.Background(), + userID: "user1", + resourceOwner: "org1", + password: "password", + authReq: &domain.AuthRequest{ + ID: "request1", + AgentID: "agent1", + }, + }, + res: res{}, + }, + { + name: "regression test old version event", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewLoginPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + domain.PasswordlessTypeNotAllowed, + "", + time.Hour*1, + time.Hour*2, + time.Hour*3, + time.Hour*4, + time.Hour*5, + ), + ), + ), + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "username", + "firstname", + "lastname", + "nickname", + "displayname", + language.German, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusher( + &user.HumanPasswordChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + user.HumanPasswordChangedType, + ), + Secret: &crypto.CryptoValue{ + CryptoType: crypto.TypeHash, + Algorithm: "plain", + KeyID: "", + Crypted: []byte("$plain$v$password"), + }, + ChangeRequired: false, + }, + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + user.NewHumanPasswordCheckSucceededEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "request1", + UserAgentID: "agent1", + }, + ), + ), + eventFromEventPusher( + user.NewHumanPasswordHashUpdatedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "$plain$x$password", + ), + ), + }, + ), + ), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1613,8 +1764,8 @@ func TestCommandSide_CheckPassword(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: tt.fields.userPasswordAlg, + eventstore: tt.fields.eventstore, + userPasswordHasher: tt.fields.userPasswordHasher, } err := r.HumanCheckPassword(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.password, tt.args.authReq, tt.args.lockoutPolicy) if tt.res.err == nil { @@ -1626,3 +1777,41 @@ func TestCommandSide_CheckPassword(t *testing.T) { }) } } + +func Test_convertPasswapErr(t *testing.T) { + type args struct { + err error + } + tests := []struct { + name string + args args + wantErr error + }{ + { + name: "nil", + args: args{nil}, + wantErr: nil, + }, + { + name: "mismatch", + args: args{passwap.ErrPasswordMismatch}, + wantErr: caos_errs.ThrowInvalidArgument(passwap.ErrPasswordMismatch, "COMMAND-3M0fs", "Errors.User.Password.Invalid"), + }, + { + name: "no change", + args: args{passwap.ErrPasswordNoChange}, + wantErr: caos_errs.ThrowPreconditionFailed(passwap.ErrPasswordNoChange, "COMMAND-Aesh5", "Errors.User.Password.NotChanged"), + }, + { + name: "other", + args: args{io.ErrClosedPipe}, + wantErr: caos_errs.ThrowInternal(io.ErrClosedPipe, "COMMAND-CahN2", "Errors.Internal"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := convertPasswapErr(tt.args.err) + assert.ErrorIs(t, err, tt.wantErr) + }) + } +} diff --git a/internal/command/user_human_test.go b/internal/command/user_human_test.go index 5d6f131c2..384ef4757 100644 --- a/internal/command/user_human_test.go +++ b/internal/command/user_human_test.go @@ -20,18 +20,17 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/id" id_mock "github.com/zitadel/zitadel/internal/id/mock" - "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/user" ) func TestCommandSide_AddHuman(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - idGenerator id.Generator - userPasswordAlg crypto.HashAlgorithm - codeAlg crypto.EncryptionAlgorithm - newCode cryptoCodeFunc + eventstore func(t *testing.T) *eventstore.Eventstore + idGenerator id.Generator + userPasswordHasher *crypto.PasswordHasher + codeAlg crypto.EncryptionAlgorithm + newCode cryptoCodeFunc } type args struct { ctx context.Context @@ -48,7 +47,6 @@ func TestCommandSide_AddHuman(t *testing.T) { } userAgg := user.NewAggregate("user1", "org1") - instanceAgg := instance.NewAggregate("instance") tests := []struct { name string @@ -59,9 +57,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "orgid missing, invalid argument error", fields: fields{ - eventstore: eventstoreExpect( - t, - ), + eventstore: expectEventstore(), }, args: args{ ctx: context.Background(), @@ -85,9 +81,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "user invalid, invalid argument error", fields: fields{ - eventstore: eventstoreExpect( - t, - ), + eventstore: expectEventstore(), }, args: args{ ctx: context.Background(), @@ -107,11 +101,10 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "with id, already exists, precondition error", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( - newAddHumanEvent("password", true, ""), + newAddHumanEvent("$plain$x$password", true, ""), ), ), ), @@ -141,8 +134,7 @@ func TestCommandSide_AddHuman(t *testing.T) { name: "domain policy not found, precondition error", fields: fields{ idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter(), expectFilter(), @@ -172,8 +164,7 @@ func TestCommandSide_AddHuman(t *testing.T) { name: "password policy not found, precondition error", fields: fields{ idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -214,8 +205,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human (with initial code), ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -227,21 +217,6 @@ func TestCommandSide_AddHuman(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewSecretGeneratorAddedEvent( - context.Background(), - &instanceAgg.Aggregate, - domain.SecretGeneratorTypeInitCode, - 0, - 1*time.Hour, - true, - true, - true, - true, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -265,7 +240,7 @@ func TestCommandSide_AddHuman(t *testing.T) { CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "id", - Crypted: []byte(""), + Crypted: []byte("userinit"), }, time.Hour*1, ), @@ -276,6 +251,7 @@ func TestCommandSide_AddHuman(t *testing.T) { ), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("userinit", time.Hour), }, args: args{ ctx: context.Background(), @@ -304,8 +280,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human (with password and initial code), ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -329,25 +304,10 @@ func TestCommandSide_AddHuman(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewSecretGeneratorAddedEvent( - context.Background(), - &instanceAgg.Aggregate, - domain.SecretGeneratorTypeInitCode, - 0, - 1*time.Hour, - true, - true, - true, - true, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, ""), + newAddHumanEvent("$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -356,7 +316,7 @@ func TestCommandSide_AddHuman(t *testing.T) { CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "id", - Crypted: []byte(""), + Crypted: []byte("userinit"), }, 1*time.Hour, ), @@ -365,9 +325,10 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("userinit", time.Hour), }, args: args{ ctx: context.Background(), @@ -395,8 +356,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human (with password and email code custom template), ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -423,7 +383,7 @@ func TestCommandSide_AddHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, ""), + newAddHumanEvent("$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanEmailCodeAddedEventV2(context.Background(), @@ -443,10 +403,10 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), - newCode: mockCode("emailCode", time.Hour), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("emailCode", time.Hour), }, args: args{ ctx: context.Background(), @@ -475,8 +435,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human (with password and return email code), ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -503,7 +462,7 @@ func TestCommandSide_AddHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, ""), + newAddHumanEvent("$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanEmailCodeAddedEventV2(context.Background(), @@ -523,10 +482,10 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), - newCode: mockCode("emailCode", time.Hour), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("emailCode", time.Hour), }, args: args{ ctx: context.Background(), @@ -556,8 +515,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human email verified, ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -584,7 +542,7 @@ func TestCommandSide_AddHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", true, ""), + newAddHumanEvent("$plain$x$password", true, ""), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent(context.Background(), @@ -594,9 +552,9 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: context.Background(), @@ -626,8 +584,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human email verified, trim spaces, ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -654,7 +611,7 @@ func TestCommandSide_AddHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", true, ""), + newAddHumanEvent("$plain$x$password", true, ""), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent(context.Background(), @@ -664,9 +621,9 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: context.Background(), @@ -696,8 +653,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human, email verified, userLoginMustBeDomain false, ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -724,7 +680,7 @@ func TestCommandSide_AddHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", true, ""), + newAddHumanEvent("$plain$x$password", true, ""), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent(context.Background(), @@ -734,9 +690,9 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", false)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: context.Background(), @@ -766,8 +722,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human claimed domain, userLoginMustBeDomain false, error", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -788,9 +743,9 @@ func TestCommandSide_AddHuman(t *testing.T) { ), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: context.Background(), @@ -819,8 +774,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human domain, userLoginMustBeDomain false, ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -868,12 +822,7 @@ func TestCommandSide_AddHuman(t *testing.T) { "email@test.ch", true, ) - event.AddPasswordData(&crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, true) + event.AddPasswordData("$plain$x$password", true) return event }(), ), @@ -885,9 +834,9 @@ func TestCommandSide_AddHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username@test.ch", "org1", false)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: context.Background(), @@ -918,8 +867,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human (with phone), ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -943,25 +891,10 @@ func TestCommandSide_AddHuman(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewSecretGeneratorAddedEvent( - context.Background(), - &instanceAgg.Aggregate, - domain.SecretGeneratorTypeVerifyPhoneCode, - 0, - 1*time.Hour, - true, - true, - true, - true, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, "+41711234567"), + newAddHumanEvent("$plain$x$password", false, "+41711234567"), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent( @@ -976,16 +909,17 @@ func TestCommandSide_AddHuman(t *testing.T) { CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "id", - Crypted: []byte(""), + Crypted: []byte("phonecode"), }, time.Hour*1)), }, uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("phonecode", time.Hour), }, args: args{ ctx: context.Background(), @@ -1017,8 +951,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human (with verified phone), ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -1030,21 +963,6 @@ func TestCommandSide_AddHuman(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewSecretGeneratorAddedEvent( - context.Background(), - &instanceAgg.Aggregate, - domain.SecretGeneratorTypeInitCode, - 0, - 1*time.Hour, - true, - true, - true, - true, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -1058,7 +976,7 @@ func TestCommandSide_AddHuman(t *testing.T) { CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "id", - Crypted: []byte(""), + Crypted: []byte("userinit"), }, 1*time.Hour, ), @@ -1075,6 +993,7 @@ func TestCommandSide_AddHuman(t *testing.T) { ), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("userinit", time.Hour), }, args: args{ ctx: context.Background(), @@ -1105,8 +1024,7 @@ func TestCommandSide_AddHuman(t *testing.T) { { name: "add human with metadata, ok", fields: fields{ - eventstore: eventstoreExpect( - t, + eventstore: expectEventstore( expectFilter(), expectFilter( eventFromEventPusher( @@ -1118,21 +1036,6 @@ func TestCommandSide_AddHuman(t *testing.T) { ), ), ), - expectFilter( - eventFromEventPusher( - instance.NewSecretGeneratorAddedEvent( - context.Background(), - &instanceAgg.Aggregate, - domain.SecretGeneratorTypeInitCode, - 0, - 1*time.Hour, - true, - true, - true, - true, - ), - ), - ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -1146,7 +1049,7 @@ func TestCommandSide_AddHuman(t *testing.T) { CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "id", - Crypted: []byte(""), + Crypted: []byte("userinit"), }, 1*time.Hour, ), @@ -1165,6 +1068,7 @@ func TestCommandSide_AddHuman(t *testing.T) { ), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + newCode: mockCode("userinit", time.Hour), }, args: args{ ctx: context.Background(), @@ -1198,11 +1102,11 @@ func TestCommandSide_AddHuman(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: tt.fields.userPasswordAlg, - userEncryption: tt.fields.codeAlg, - idGenerator: tt.fields.idGenerator, - newCode: tt.fields.newCode, + eventstore: tt.fields.eventstore(t), + userPasswordHasher: tt.fields.userPasswordHasher, + userEncryption: tt.fields.codeAlg, + idGenerator: tt.fields.idGenerator, + newCode: tt.fields.newCode, } err := r.AddHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.allowInitMail) if tt.res.err == nil { @@ -1224,9 +1128,9 @@ func TestCommandSide_AddHuman(t *testing.T) { func TestCommandSide_ImportHuman(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - idGenerator id.Generator - userPasswordAlg crypto.HashAlgorithm + eventstore *eventstore.Eventstore + idGenerator id.Generator + userPasswordHasher *crypto.PasswordHasher } type args struct { ctx context.Context @@ -1410,7 +1314,7 @@ func TestCommandSide_ImportHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", true, ""), + newAddHumanEvent("$plain$x$password", true, ""), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -1428,8 +1332,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1501,7 +1405,7 @@ func TestCommandSide_ImportHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, ""), + newAddHumanEvent("$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent(context.Background(), @@ -1511,8 +1415,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1610,8 +1514,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1694,7 +1598,7 @@ func TestCommandSide_ImportHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, ""), + newAddHumanEvent("$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent(context.Background(), @@ -1717,8 +1621,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1804,7 +1708,7 @@ func TestCommandSide_ImportHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, "+41711234567"), + newAddHumanEvent("$plain$x$password", false, "+41711234567"), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -1832,8 +1736,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -1911,7 +1815,7 @@ func TestCommandSide_ImportHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newAddHumanEvent("password", false, "+41711234567"), + newAddHumanEvent("$plain$x$password", false, "+41711234567"), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -1933,8 +1837,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -2064,8 +1968,8 @@ func TestCommandSide_ImportHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("idpID", "externalID")), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -2116,9 +2020,9 @@ func TestCommandSide_ImportHuman(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - idGenerator: tt.fields.idGenerator, - userPasswordAlg: tt.fields.userPasswordAlg, + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + userPasswordHasher: tt.fields.userPasswordHasher, } gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless, tt.args.links, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator) if tt.res.err == nil { @@ -2137,9 +2041,9 @@ func TestCommandSide_ImportHuman(t *testing.T) { func TestCommandSide_RegisterHuman(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - idGenerator id.Generator - userPasswordAlg crypto.HashAlgorithm + eventstore *eventstore.Eventstore + idGenerator id.Generator + userPasswordHasher *crypto.PasswordHasher } type args struct { ctx context.Context @@ -2342,6 +2246,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2411,6 +2316,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2480,6 +2386,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2566,6 +2473,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2612,7 +2520,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("email@test.ch", "password", false, ""), + newRegisterHumanEvent("email@test.ch", "$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -2630,8 +2538,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("email@test.ch", "org1", false)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -2710,6 +2618,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2723,7 +2632,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("username", "password", false, ""), + newRegisterHumanEvent("username", "$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -2741,8 +2650,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", false)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -2822,6 +2731,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2835,7 +2745,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("username", "password", false, ""), + newRegisterHumanEvent("username", "$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -2853,8 +2763,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -2934,6 +2844,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -2947,7 +2858,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("username", "password", false, ""), + newRegisterHumanEvent("username", "$plain$x$password", false, ""), ), eventFromEventPusher( user.NewHumanEmailVerifiedEvent(context.Background(), @@ -2957,8 +2868,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -3040,6 +2951,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -3053,7 +2965,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("username", "password", false, "+41711234567"), + newRegisterHumanEvent("username", "$plain$x$password", false, "+41711234567"), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -3081,8 +2993,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -3168,6 +3080,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -3181,7 +3094,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("username", "password", false, "+41711234567"), + newRegisterHumanEvent("username", "$plain$x$password", false, "+41711234567"), ), eventFromEventPusher( user.NewHumanInitialCodeAddedEvent(context.Background(), @@ -3203,8 +3116,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -3291,6 +3204,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { false, false, false, + false, domain.PasswordlessTypeNotAllowed, "", time.Hour*1, @@ -3336,7 +3250,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) { expectPush( []*repository.Event{ eventFromEventPusher( - newRegisterHumanEvent("username", "password", false, ""), + newRegisterHumanEvent("username", "$plain$x$password", false, ""), ), eventFromEventPusher( user.NewUserIDPLinkAddedEvent(context.Background(), @@ -3355,8 +3269,8 @@ func TestCommandSide_RegisterHuman(t *testing.T) { uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("idpID", "externalID")), ), ), - idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), - userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + userPasswordHasher: mockPasswordHasher("x"), }, args: args{ ctx: context.Background(), @@ -3407,9 +3321,9 @@ func TestCommandSide_RegisterHuman(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - idGenerator: tt.fields.idGenerator, - userPasswordAlg: tt.fields.userPasswordAlg, + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + userPasswordHasher: tt.fields.userPasswordHasher, } got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator) if tt.res.err == nil { @@ -3748,13 +3662,7 @@ func newAddHumanEvent(password string, changeRequired bool, phone string) *user. true, ) if password != "" { - event.AddPasswordData(&crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte(password), - }, - changeRequired) + event.AddPasswordData(password, changeRequired) } if phone != "" { event.AddPhoneData(domain.PhoneNumber(phone)) @@ -3776,13 +3684,7 @@ func newRegisterHumanEvent(username, password string, changeRequired bool, phone true, ) if password != "" { - event.AddPasswordData(&crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte(password), - }, - changeRequired) + event.AddPasswordData(password, changeRequired) } if phone != "" { event.AddPhoneData(domain.PhoneNumber(phone)) @@ -3797,7 +3699,7 @@ func TestAddHumanCommand(t *testing.T) { type args struct { human *AddHuman orgID string - passwordAlg crypto.HashAlgorithm + hasher *crypto.PasswordHasher filter preparation.FilterToQueryReducer codeAlg crypto.EncryptionAlgorithm allowInitMail bool @@ -3854,6 +3756,24 @@ func TestAddHumanCommand(t *testing.T) { ValidationErr: caos_errs.ThrowInvalidArgument(nil, "USER-4hB7d", "Errors.User.Profile.LastNameEmpty"), }, }, + { + name: "unsupported password hash encoding", + args: args{ + human: &AddHuman{ + Email: Email{Address: "support@zitadel.com", Verified: true}, + PreferredLanguage: language.English, + FirstName: "gigi", + LastName: "giraffe", + EncodedPasswordHash: "$foo$x$password", + Username: "username", + }, + orgID: "ro", + hasher: mockPasswordHasher("x"), + }, + want: Want{ + ValidationErr: caos_errs.ThrowInvalidArgument(nil, "USER-JDk4t", "Errors.User.Password.NotSupported"), + }, + }, { name: "invalid password", fields: fields{ @@ -3919,9 +3839,9 @@ func TestAddHumanCommand(t *testing.T) { Password: "password", Username: "username", }, - orgID: "ro", - passwordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)), - codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + orgID: "ro", + hasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), filter: NewMultiFilter().Append( func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) { return []eventstore.Event{}, nil @@ -3970,12 +3890,79 @@ func TestAddHumanCommand(t *testing.T) { "support@zitadel.com", true, ) - event.AddPasswordData(&crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: "hash", - KeyID: "", - Crypted: []byte("password"), - }, false) + event.AddPasswordData("$plain$x$password", false) + return event + }(), + user.NewHumanEmailVerifiedEvent(context.Background(), &agg.Aggregate), + }, + }, + }, + { + name: "hashed password", + fields: fields{ + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id"), + }, + args: args{ + human: &AddHuman{ + Email: Email{Address: "support@zitadel.com", Verified: true}, + PreferredLanguage: language.English, + FirstName: "gigi", + LastName: "giraffe", + EncodedPasswordHash: "$plain$x$password", + Username: "username", + }, + orgID: "ro", + hasher: mockPasswordHasher("x"), + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + filter: NewMultiFilter().Append( + func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) { + return []eventstore.Event{}, nil + }). + Append( + func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) { + return []eventstore.Event{ + org.NewDomainPolicyAddedEvent( + ctx, + &org.NewAggregate("id").Aggregate, + true, + true, + true, + ), + }, nil + }). + Append( + func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) { + return []eventstore.Event{ + org.NewPasswordComplexityPolicyAddedEvent( + ctx, + &org.NewAggregate("id").Aggregate, + 2, + false, + false, + false, + false, + ), + }, nil + }). + Filter(), + }, + want: Want{ + Commands: []eventstore.Command{ + func() *user.HumanAddedEvent { + event := user.NewHumanAddedEvent( + context.Background(), + &agg.Aggregate, + "username", + "gigi", + "giraffe", + "", + "gigi giraffe", + language.English, + 0, + "support@zitadel.com", + true, + ) + event.AddPasswordData("$plain$x$password", false) return event }(), user.NewHumanEmailVerifiedEvent(context.Background(), &agg.Aggregate), @@ -3988,7 +3975,7 @@ func TestAddHumanCommand(t *testing.T) { c := &Commands{ idGenerator: tt.fields.idGenerator, } - AssertValidation(t, context.Background(), c.AddHumanCommand(tt.args.human, tt.args.orgID, tt.args.passwordAlg, tt.args.codeAlg, tt.args.allowInitMail), tt.args.filter, tt.want) + AssertValidation(t, context.Background(), c.AddHumanCommand(tt.args.human, tt.args.orgID, tt.args.hasher, tt.args.codeAlg, tt.args.allowInitMail), tt.args.filter, tt.want) }) } } diff --git a/internal/command/user_machine_secret.go b/internal/command/user_machine_secret.go index a7a91b247..8f28b5e5d 100644 --- a/internal/command/user_machine_secret.go +++ b/internal/command/user_machine_secret.go @@ -113,7 +113,7 @@ func prepareRemoveMachineSecret(a *user.Aggregate) preparation.Validation { func (c *Commands) VerifyMachineSecret(ctx context.Context, userID string, resourceOwner string, secret string) (*domain.ObjectDetails, error) { agg := user.NewAggregate(userID, resourceOwner) - cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareVerifyMachineSecret(agg, secret, c.userPasswordAlg)) + cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareVerifyMachineSecret(agg, secret, c.codeAlg)) if err != nil { return nil, err } diff --git a/internal/command/user_machine_secret_test.go b/internal/command/user_machine_secret_test.go index 490797b96..42df770d9 100644 --- a/internal/command/user_machine_secret_test.go +++ b/internal/command/user_machine_secret_test.go @@ -529,8 +529,8 @@ func TestCommandSide_VerifyMachineSecret(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, - userPasswordAlg: crypto.NewBCrypt(14), + eventstore: tt.fields.eventstore, + codeAlg: crypto.NewBCrypt(14), } got, err := r.VerifyMachineSecret(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.secret) if tt.res.err == nil { diff --git a/internal/command/user_v2_passkey.go b/internal/command/user_v2_passkey.go index f08a0632c..47af8c134 100644 --- a/internal/command/user_v2_passkey.go +++ b/internal/command/user_v2_passkey.go @@ -7,6 +7,7 @@ import ( "github.com/zitadel/logging" "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" @@ -132,7 +133,7 @@ func (c *Commands) addUserPasskeyCode(ctx context.Context, userID, resourceOwner if err != nil { return nil, err } - code, err := c.newCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) + code, err := c.newPasskeyCode(ctx, c.eventstore.Filter, alg) if err != nil { return nil, err } @@ -154,3 +155,7 @@ func (c *Commands) addUserPasskeyCode(ctx context.Context, userID, resourceOwner Code: code.Plain, }, nil } + +func (c *Commands) newPasskeyCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) { + return c.newCode(ctx, filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) +} diff --git a/internal/command/user_v2_passkey_test.go b/internal/command/user_v2_passkey_test.go index 1885f6ab2..8a96d4a21 100644 --- a/internal/command/user_v2_passkey_test.go +++ b/internal/command/user_v2_passkey_test.go @@ -139,7 +139,7 @@ func TestCommands_RegisterUserPasskeyWithCode(t *testing.T) { es := eventstoreExpect(t, expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))), ) - code, err := newCryptoCodeWithExpiry(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) + code, err := newCryptoCode(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) require.NoError(t, err) userAgg := &user.NewAggregate("user1", "org1").Aggregate type fields struct { @@ -237,7 +237,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) { es := eventstoreExpect(t, expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))), ) - code, err := newCryptoCodeWithExpiry(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) + code, err := newCryptoCode(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) require.NoError(t, err) userAgg := &user.NewAggregate("user1", "org1").Aggregate @@ -463,7 +463,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) { userAgg := &user.NewAggregate("user1", "org1").Aggregate type fields struct { newCode cryptoCodeFunc - eventstore *eventstore.Eventstore + eventstore func(t *testing.T) *eventstore.Eventstore idGenerator id.Generator } type args struct { @@ -480,8 +480,8 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) { { name: "id generator error", fields: fields{ - newCode: newCryptoCodeWithExpiry, - eventstore: eventstoreExpect(t), + newCode: mockCode("passkey1", time.Hour), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe), }, args: args{ @@ -494,7 +494,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) { name: "success", fields: fields{ newCode: mockCode("passkey1", time.Minute), - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(eventFromEventPusher( user.NewHumanAddedEvent(context.Background(), userAgg, @@ -538,7 +538,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c := &Commands{ newCode: tt.fields.newCode, - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, } got, err := c.AddUserPasskeyCode(context.Background(), tt.args.userID, tt.args.resourceOwner, alg) @@ -572,7 +572,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) { { name: "template error", fields: fields{ - newCode: newCryptoCodeWithExpiry, + newCode: newCryptoCode, eventstore: eventstoreExpect(t), }, args: args{ @@ -585,7 +585,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) { { name: "id generator error", fields: fields{ - newCode: newCryptoCodeWithExpiry, + newCode: newCryptoCode, eventstore: eventstoreExpect(t), idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe), }, @@ -680,7 +680,7 @@ func TestCommands_AddUserPasskeyCodeReturn(t *testing.T) { { name: "id generator error", fields: fields{ - newCode: newCryptoCodeWithExpiry, + newCode: newCryptoCode, eventstore: eventstoreExpect(t), idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe), }, @@ -774,7 +774,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) { { name: "id generator error", fields: fields{ - newCode: newCryptoCodeWithExpiry, + newCode: newCryptoCode, eventstore: eventstoreExpect(t), idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe), }, @@ -787,7 +787,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) { { name: "crypto error", fields: fields{ - newCode: newCryptoCodeWithExpiry, + newCode: newCryptoCode, eventstore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "123"), }, @@ -800,7 +800,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) { { name: "filter query error", fields: fields{ - newCode: newCryptoCodeWithExpiry, + newCode: newCryptoCode, eventstore: eventstoreExpect(t, expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))), expectFilterError(io.ErrClosedPipe), diff --git a/internal/command/user_v2_totp_test.go b/internal/command/user_v2_totp_test.go index d7b9f8246..90596428a 100644 --- a/internal/command/user_v2_totp_test.go +++ b/internal/command/user_v2_totp_test.go @@ -188,7 +188,7 @@ func TestCommands_AddUserTOTP(t *testing.T) { } func TestCommands_CheckUserTOTP(t *testing.T) { - ctx := authz.NewMockContext("inst1", "org1", "user1") + ctx := authz.NewMockContext("", "org1", "user1") cryptoAlg := crypto.CreateMockEncryptionAlg(gomock.NewController(t)) key, secret, err := domain.NewOTPKey("example.com", "user1", cryptoAlg) diff --git a/internal/config/systemdefaults/system_defaults.go b/internal/config/systemdefaults/system_defaults.go index 7ca33b04b..012c37ac0 100644 --- a/internal/config/systemdefaults/system_defaults.go +++ b/internal/config/systemdefaults/system_defaults.go @@ -8,6 +8,7 @@ import ( type SystemDefaults struct { SecretGenerators SecretGenerators + PasswordHasher crypto.PasswordHashConfig Multifactors MultifactorConfig DomainVerification DomainVerification Notifications Notifications diff --git a/internal/crypto/crypto.go b/internal/crypto/crypto.go index 748a124b5..5cc057590 100644 --- a/internal/crypto/crypto.go +++ b/internal/crypto/crypto.go @@ -10,7 +10,7 @@ import ( const ( TypeEncryption CryptoType = iota - TypeHash + TypeHash // Depcrecated: use [passwap.Swapper] instead ) type Crypto interface { @@ -26,6 +26,7 @@ type EncryptionAlgorithm interface { DecryptString(hashed []byte, keyID string) (string, error) } +// Depcrecated: use [passwap.Swapper] instead type HashAlgorithm interface { Crypto Hash(value []byte) ([]byte, error) diff --git a/internal/crypto/passwap.go b/internal/crypto/passwap.go new file mode 100644 index 000000000..cf72a844f --- /dev/null +++ b/internal/crypto/passwap.go @@ -0,0 +1,209 @@ +package crypto + +import ( + "fmt" + "strings" + + "github.com/mitchellh/mapstructure" + "github.com/zitadel/passwap" + "github.com/zitadel/passwap/argon2" + "github.com/zitadel/passwap/bcrypt" + "github.com/zitadel/passwap/md5" + "github.com/zitadel/passwap/scrypt" + "github.com/zitadel/passwap/verifier" + + "github.com/zitadel/zitadel/internal/errors" +) + +type PasswordHasher struct { + *passwap.Swapper + Prefixes []string +} + +func (h *PasswordHasher) EncodingSupported(encodedHash string) bool { + for _, prefix := range h.Prefixes { + if strings.HasPrefix(encodedHash, prefix) { + return true + } + } + return false +} + +type HashName string + +const ( + HashNameArgon2 HashName = "argon2" // used for the common argon2 verifier + HashNameArgon2i HashName = "argon2i" // hash only + HashNameArgon2id HashName = "argon2id" // hash only + HashNameBcrypt HashName = "bcrypt" // hash and verify + HashNameMd5 HashName = "md5" // verify only, as hashing with md5 is insecure and deprecated + HashNameScrypt HashName = "scrypt" // hash and verify +) + +type PasswordHashConfig struct { + Verifiers []HashName + Hasher HasherConfig +} + +func (c *PasswordHashConfig) PasswordHasher() (*PasswordHasher, error) { + verifiers, vPrefixes, err := c.buildVerifiers() + if err != nil { + return nil, errors.ThrowInvalidArgument(err, "CRYPT-sahW9", "password hash config invalid") + } + hasher, hPrefixes, err := c.Hasher.buildHasher() + if err != nil { + return nil, errors.ThrowInvalidArgument(err, "CRYPT-Que4r", "password hash config invalid") + } + return &PasswordHasher{ + Swapper: passwap.NewSwapper(hasher, verifiers...), + Prefixes: append(hPrefixes, vPrefixes...), + }, nil +} + +type prefixVerifier struct { + prefixes []string + verifier verifier.Verifier +} + +// map HashNames to Verifier instances. +var knowVerifiers = map[HashName]prefixVerifier{ + HashNameArgon2: { + // only argon2i and argon2id are suppored. + // The Prefix constant also covers argon2d. + prefixes: []string{argon2.Prefix}, + verifier: argon2.Verifier, + }, + HashNameBcrypt: { + prefixes: []string{bcrypt.Prefix}, + verifier: bcrypt.Verifier, + }, + HashNameMd5: { + prefixes: []string{md5.Prefix}, + verifier: md5.Verifier, + }, + HashNameScrypt: { + prefixes: []string{scrypt.Prefix, scrypt.Prefix_Linux}, + verifier: scrypt.Verifier, + }, +} + +func (c *PasswordHashConfig) buildVerifiers() (verifiers []verifier.Verifier, prefixes []string, err error) { + verifiers = make([]verifier.Verifier, len(c.Verifiers)) + prefixes = make([]string, 0, len(c.Verifiers)+1) + for i, name := range c.Verifiers { + v, ok := knowVerifiers[name] + if !ok { + return nil, nil, fmt.Errorf("invalid verifier %q", name) + } + verifiers[i] = v.verifier + prefixes = append(prefixes, v.prefixes...) + } + return verifiers, prefixes, nil +} + +type HasherConfig struct { + Algorithm HashName + Params map[string]any `mapstructure:",remain"` +} + +func (c *HasherConfig) buildHasher() (hasher passwap.Hasher, prefixes []string, err error) { + switch c.Algorithm { + case HashNameArgon2i: + return c.argon2i() + case HashNameArgon2id: + return c.argon2id() + case HashNameBcrypt: + return c.bcrypt() + case HashNameScrypt: + return c.scrypt() + case "": + return nil, nil, fmt.Errorf("missing hasher algorithm") + case HashNameArgon2, HashNameMd5: + fallthrough + default: + return nil, nil, fmt.Errorf("invalid algorithm %q", c.Algorithm) + } +} + +func (c *HasherConfig) decodeParams(dst any) error { + decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + ErrorUnused: true, + ErrorUnset: true, + Result: dst, + }) + if err != nil { + return err + } + return decoder.Decode(c.Params) +} + +// argon2Params decodes [HasherConfig.Params] into a [argon2.Params] used as defaults. +// p is passed a copy and therfore will not be modified. +func (c *HasherConfig) argon2Params(p argon2.Params) (argon2.Params, error) { + var dst struct { + Time uint32 `mapstructure:"Time"` + Memory uint32 `mapstructure:"Memory"` + Threads uint8 `mapstructure:"Threads"` + } + if err := c.decodeParams(&dst); err != nil { + return argon2.Params{}, fmt.Errorf("decode argon2i params: %w", err) + } + p.Time = dst.Time + p.Memory = dst.Memory + p.Threads = dst.Threads + return p, nil +} + +func (c *HasherConfig) argon2i() (passwap.Hasher, []string, error) { + p, err := c.argon2Params(argon2.RecommendedIParams) + if err != nil { + return nil, nil, err + } + return argon2.NewArgon2i(p), []string{argon2.Prefix}, nil +} + +func (c *HasherConfig) argon2id() (passwap.Hasher, []string, error) { + p, err := c.argon2Params(argon2.RecommendedIDParams) + if err != nil { + return nil, nil, err + } + return argon2.NewArgon2id(p), []string{argon2.Prefix}, nil +} + +func (c *HasherConfig) bcryptCost() (int, error) { + var dst = struct { + Cost int `mapstructure:"Cost"` + }{} + if err := c.decodeParams(&dst); err != nil { + return 0, fmt.Errorf("decode bcrypt params: %w", err) + } + return dst.Cost, nil +} + +func (c *HasherConfig) bcrypt() (passwap.Hasher, []string, error) { + cost, err := c.bcryptCost() + if err != nil { + return nil, nil, err + } + return bcrypt.New(cost), []string{bcrypt.Prefix}, nil +} + +func (c *HasherConfig) scryptParams() (scrypt.Params, error) { + var dst = struct { + Cost int `mapstructure:"Cost"` + }{} + if err := c.decodeParams(&dst); err != nil { + return scrypt.Params{}, fmt.Errorf("decode scrypt params: %w", err) + } + p := scrypt.RecommendedParams // copy + p.N = 1 << dst.Cost + return p, nil +} + +func (c *HasherConfig) scrypt() (passwap.Hasher, []string, error) { + p, err := c.scryptParams() + if err != nil { + return nil, nil, err + } + return scrypt.New(p), []string{scrypt.Prefix, scrypt.Prefix_Linux}, nil +} diff --git a/internal/crypto/passwap_test.go b/internal/crypto/passwap_test.go new file mode 100644 index 000000000..2cc5aa80e --- /dev/null +++ b/internal/crypto/passwap_test.go @@ -0,0 +1,486 @@ +package crypto + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitadel/passwap/argon2" + "github.com/zitadel/passwap/bcrypt" + "github.com/zitadel/passwap/md5" + "github.com/zitadel/passwap/scrypt" +) + +func TestPasswordHasher_EncodingSupported(t *testing.T) { + tests := []struct { + name string + encodedHash string + want bool + }{ + { + name: "empty string, false", + encodedHash: "", + want: false, + }, + { + name: "scrypt, false", + encodedHash: "$scrypt$ln=16,r=8,p=1$cmFuZG9tc2FsdGlzaGFyZA$Rh+NnJNo1I6nRwaNqbDm6kmADswD1+7FTKZ7Ln9D8nQ", + want: false, + }, + { + name: "bcrypt, true", + encodedHash: "$2y$12$hXUrnqdq1RIIYZ2HPytIIe5lXdIvbhqrTvdPsSF7o.jFh817Z6lwm", + want: true, + }, + { + name: "argo2i, true", + encodedHash: "$argon2i$v=19$m=4096,t=3,p=1$cmFuZG9tc2FsdGlzaGFyZA$YMvo8AUoNtnKYGqeODruCjHdiEbl1pKL2MsYy9VgU/E", + want: true, + }, + { + name: "argo2id, true", + encodedHash: "$argon2d$v=19$m=4096,t=3,p=1$cmFuZG9tc2FsdGlzaGFyZA$CB0Du96aj3fQVcVSqb0LIA6Z6fpStjzjVkaC3RlpK9A", + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := &PasswordHasher{ + Prefixes: []string{bcrypt.Prefix, argon2.Prefix}, + } + got := h.EncodingSupported(tt.encodedHash) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestPasswordHashConfig_PasswordHasher(t *testing.T) { + type fields struct { + Verifiers []HashName + Hasher HasherConfig + } + tests := []struct { + name string + fields fields + wantPrefixes []string + wantErr bool + }{ + { + name: "invalid verifier", + fields: fields{ + Verifiers: []HashName{ + HashNameArgon2, + HashNameBcrypt, + HashNameMd5, + HashNameScrypt, + "foobar", + }, + Hasher: HasherConfig{ + Algorithm: HashNameBcrypt, + Params: map[string]any{ + "cost": 5, + }, + }, + }, + wantErr: true, + }, + { + name: "invalid hasher", + fields: fields{ + Verifiers: []HashName{ + HashNameArgon2, + HashNameBcrypt, + HashNameMd5, + HashNameScrypt, + }, + Hasher: HasherConfig{ + Algorithm: "foobar", + Params: map[string]any{ + "cost": 5, + }, + }, + }, + wantErr: true, + }, + { + name: "missing algorithm", + fields: fields{ + Hasher: HasherConfig{}, + }, + wantErr: true, + }, + { + name: "invalid md5", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameMd5, + }, + }, + wantErr: true, + }, + { + name: "invalid argon2", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameArgon2, + Params: map[string]any{ + "time": 3, + "memory": 32768, + "threads": 4, + }, + }, + }, + wantErr: true, + }, + { + name: "argon2i, error", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameArgon2i, + Params: map[string]any{ + "time": 3, + "threads": 4, + }, + }, + }, + wantErr: true, + }, + { + name: "argon2i, ok", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameArgon2i, + Params: map[string]any{ + "time": 3, + "memory": 32768, + "threads": 4, + }, + }, + Verifiers: []HashName{HashNameBcrypt, HashNameMd5, HashNameScrypt}, + }, + wantPrefixes: []string{argon2.Prefix, bcrypt.Prefix, md5.Prefix, scrypt.Prefix, scrypt.Prefix_Linux}, + }, + { + name: "argon2id, error", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameArgon2id, + Params: map[string]any{ + "time": 3, + "threads": 4, + }, + }, + }, + wantErr: true, + }, + { + name: "argon2id, ok", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameArgon2id, + Params: map[string]any{ + "time": 3, + "memory": 32768, + "threads": 4, + }, + }, + Verifiers: []HashName{HashNameBcrypt, HashNameMd5, HashNameScrypt}, + }, + wantPrefixes: []string{argon2.Prefix, bcrypt.Prefix, md5.Prefix, scrypt.Prefix, scrypt.Prefix_Linux}, + }, + { + name: "bcrypt, error", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameBcrypt, + Params: map[string]any{ + "foo": 3, + }, + }, + }, + wantErr: true, + }, + { + name: "bcrypt, ok", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameBcrypt, + Params: map[string]any{ + "cost": 3, + }, + }, + Verifiers: []HashName{HashNameArgon2, HashNameMd5, HashNameScrypt}, + }, + wantPrefixes: []string{bcrypt.Prefix, argon2.Prefix, md5.Prefix, scrypt.Prefix, scrypt.Prefix_Linux}, + }, + { + name: "scrypt, error", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameScrypt, + Params: map[string]any{ + "cost": "bar", + }, + }, + }, + wantErr: true, + }, + { + name: "scrypt, ok", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameScrypt, + Params: map[string]any{ + "cost": 3, + }, + }, + Verifiers: []HashName{HashNameArgon2, HashNameBcrypt, HashNameMd5}, + }, + wantPrefixes: []string{scrypt.Prefix, scrypt.Prefix_Linux, argon2.Prefix, bcrypt.Prefix, md5.Prefix}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &PasswordHashConfig{ + Verifiers: tt.fields.Verifiers, + Hasher: tt.fields.Hasher, + } + got, err := c.PasswordHasher() + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + if tt.wantPrefixes != nil { + require.NotNil(t, got) + assert.Equal(t, tt.wantPrefixes, got.Prefixes) + encoded, err := got.Hash("password") + require.NoError(t, err) + assert.NotEmpty(t, encoded) + } + }) + } +} + +func TestHasherConfig_decodeParams(t *testing.T) { + type dst struct { + A int + B uint32 + } + tests := []struct { + name string + params map[string]any + want dst + wantErr bool + }{ + { + name: "unused", + params: map[string]any{ + "a": 1, + "b": 2, + "c": 3, + }, + wantErr: true, + }, + { + name: "unset", + params: map[string]any{ + "a": 1, + }, + wantErr: true, + }, + { + name: "wrong type", + params: map[string]any{ + "a": 1, + "b": "2", + }, + wantErr: true, + }, + { + name: "ok", + params: map[string]any{ + "a": 1, + "b": 2, + }, + want: dst{ + A: 1, + B: 2, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &HasherConfig{ + Params: tt.params, + } + var got dst + err := c.decodeParams(&got) + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestHasherConfig_argon2Params(t *testing.T) { + type fields struct { + Params map[string]any + } + type args struct { + p argon2.Params + } + tests := []struct { + name string + fields fields + args args + want argon2.Params + wantErr bool + }{ + { + name: "decode error", + fields: fields{ + Params: map[string]any{ + "foo": "bar", + }, + }, + args: args{ + p: argon2.RecommendedIDParams, + }, + wantErr: true, + }, + { + name: "ok", + fields: fields{ + Params: map[string]any{ + "time": 2, + "memory": 256, + "threads": 8, + }, + }, + args: args{ + p: argon2.RecommendedIDParams, + }, + want: argon2.Params{ + Time: 2, + Memory: 256, + Threads: 8, + KeyLen: 32, + SaltLen: 16, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &HasherConfig{ + Params: tt.fields.Params, + } + got, err := c.argon2Params(tt.args.p) + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestHasherConfig_bcryptCost(t *testing.T) { + type fields struct { + Params map[string]any + } + tests := []struct { + name string + fields fields + want int + wantErr bool + }{ + { + name: "decode error", + fields: fields{ + Params: map[string]any{ + "foo": "bar", + }, + }, + wantErr: true, + }, + { + name: "ok", + fields: fields{ + Params: map[string]any{ + "cost": 12, + }, + }, + want: 12, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &HasherConfig{ + Params: tt.fields.Params, + } + got, err := c.bcryptCost() + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestHasherConfig_scryptParams(t *testing.T) { + type fields struct { + Params map[string]any + } + tests := []struct { + name string + fields fields + want scrypt.Params + wantErr bool + }{ + { + name: "decode error", + fields: fields{ + Params: map[string]any{ + "foo": "bar", + }, + }, + wantErr: true, + }, + { + name: "ok", + fields: fields{ + Params: map[string]any{ + "cost": 2, + }, + }, + want: scrypt.Params{ + N: 4, + R: 8, + P: 1, + KeyLen: 32, + SaltLen: 16, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &HasherConfig{ + Params: tt.fields.Params, + } + got, err := c.scryptParams() + if tt.wantErr { + assert.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/domain/auth_request.go b/internal/domain/auth_request.go index c0b9e1a40..765fead8a 100644 --- a/internal/domain/auth_request.go +++ b/internal/domain/auth_request.go @@ -116,6 +116,17 @@ const ( MFALevelMultiFactorCertified ) +type AuthRequestState int + +const ( + AuthRequestStateUnspecified AuthRequestState = iota + AuthRequestStateAdded + AuthRequestStateCodeAdded + AuthRequestStateCodeExchanged + AuthRequestStateFailed + AuthRequestStateSucceeded +) + func NewAuthRequestFromType(requestType AuthRequestType) (*AuthRequest, error) { switch requestType { case AuthRequestTypeOIDC: diff --git a/internal/domain/human.go b/internal/domain/human.go index 619eaf480..0454a3665 100644 --- a/internal/domain/human.go +++ b/internal/domain/human.go @@ -16,7 +16,7 @@ type Human struct { Username string State UserState *Password - *HashedPassword + HashedPassword string *Profile *Email *Phone @@ -103,10 +103,10 @@ func (u *Human) EnsureDisplayName() { u.DisplayName = u.Username } -func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, passwordAlg crypto.HashAlgorithm, onetime bool) error { +func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, hasher *crypto.PasswordHasher, onetime bool) error { if u.Password != nil { u.Password.ChangeRequired = onetime - return u.Password.HashPasswordIfExisting(policy, passwordAlg) + return u.Password.HashPasswordIfExisting(policy, hasher) } return nil } @@ -115,7 +115,7 @@ func (u *Human) IsInitialState(passwordless, externalIDPs bool) bool { if externalIDPs { return false } - return u.Email == nil || !u.IsEmailVerified || !passwordless && (u.Password == nil || u.Password.SecretString == "") && (u.HashedPassword == nil || u.HashedPassword.SecretString == "") + return u.Email == nil || !u.IsEmailVerified || !passwordless && (u.Password == nil || u.Password.SecretString == "") && u.HashedPassword == "" } func NewInitUserCode(generator crypto.Generator) (*InitUserCode, error) { diff --git a/internal/domain/human_hashed_password.go b/internal/domain/human_hashed_password.go deleted file mode 100644 index 5aa144fe5..000000000 --- a/internal/domain/human_hashed_password.go +++ /dev/null @@ -1,24 +0,0 @@ -package domain - -import ( - "github.com/zitadel/zitadel/internal/crypto" - es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" -) - -type HashedPassword struct { - es_models.ObjectRoot - - SecretString string - SecretCrypto *crypto.CryptoValue -} - -func NewHashedPassword(password, algorithm string) *HashedPassword { - return &HashedPassword{ - SecretString: password, - SecretCrypto: &crypto.CryptoValue{ - CryptoType: crypto.TypeHash, - Algorithm: algorithm, - Crypted: []byte(password), - }, - } -} diff --git a/internal/domain/human_password.go b/internal/domain/human_password.go index 070d00aca..35bcbeaf2 100644 --- a/internal/domain/human_password.go +++ b/internal/domain/human_password.go @@ -12,7 +12,7 @@ type Password struct { es_models.ObjectRoot SecretString string - SecretCrypto *crypto.CryptoValue + EncodedSecret string ChangeRequired bool } @@ -30,7 +30,7 @@ type PasswordCode struct { NotificationType NotificationType } -func (p *Password) HashPasswordIfExisting(policy *PasswordComplexityPolicy, passwordAlg crypto.HashAlgorithm) error { +func (p *Password) HashPasswordIfExisting(policy *PasswordComplexityPolicy, hasher *crypto.PasswordHasher) error { if p.SecretString == "" { return nil } @@ -40,11 +40,11 @@ func (p *Password) HashPasswordIfExisting(policy *PasswordComplexityPolicy, pass if err := policy.Check(p.SecretString); err != nil { return err } - secret, err := crypto.Hash([]byte(p.SecretString), passwordAlg) + encoded, err := hasher.Hash(p.SecretString) if err != nil { return err } - p.SecretCrypto = secret + p.EncodedSecret = encoded return nil } diff --git a/internal/domain/idp.go b/internal/domain/idp.go index d06fcdd1f..c2664c1ab 100644 --- a/internal/domain/idp.go +++ b/internal/domain/idp.go @@ -48,12 +48,13 @@ func (t IDPType) GetCSSClass() string { case IDPTypeGitLab, IDPTypeGitLabSelfHosted: return "gitlab" + case IDPTypeAzureAD: + return "azure" case IDPTypeUnspecified, IDPTypeOIDC, IDPTypeJWT, IDPTypeOAuth, - IDPTypeLDAP, - IDPTypeAzureAD: + IDPTypeLDAP: fallthrough default: return "" diff --git a/internal/domain/oidc_error_reason.go b/internal/domain/oidc_error_reason.go new file mode 100644 index 000000000..5a4c8d2c7 --- /dev/null +++ b/internal/domain/oidc_error_reason.go @@ -0,0 +1,23 @@ +package domain + +type OIDCErrorReason int32 + +const ( + OIDCErrorReasonUnspecified OIDCErrorReason = iota + OIDCErrorReasonInvalidRequest + OIDCErrorReasonUnauthorizedClient + OIDCErrorReasonAccessDenied + OIDCErrorReasonUnsupportedResponseType + OIDCErrorReasonInvalidScope + OIDCErrorReasonServerError + OIDCErrorReasonTemporaryUnavailable + OIDCErrorReasonInteractionRequired + OIDCErrorReasonLoginRequired + OIDCErrorReasonAccountSelectionRequired + OIDCErrorReasonConsentRequired + OIDCErrorReasonInvalidRequestURI + OIDCErrorReasonInvalidRequestObject + OIDCErrorReasonRequestNotSupported + OIDCErrorReasonRequestURINotSupported + OIDCErrorReasonRegistrationNotSupported +) diff --git a/internal/domain/oidc_session.go b/internal/domain/oidc_session.go new file mode 100644 index 000000000..ad09f1073 --- /dev/null +++ b/internal/domain/oidc_session.go @@ -0,0 +1,9 @@ +package domain + +type OIDCSessionState int32 + +const ( + OIDCSessionStateUnspecified OIDCSessionState = iota + OIDCSessionStateActive + OIDCSessionStateTerminated +) diff --git a/internal/domain/org_domain.go b/internal/domain/org_domain.go index 6009639ed..ad39e3679 100644 --- a/internal/domain/org_domain.go +++ b/internal/domain/org_domain.go @@ -1,6 +1,7 @@ package domain import ( + "regexp" "strings" http_util "github.com/zitadel/zitadel/internal/api/http" @@ -32,7 +33,38 @@ func (domain *OrgDomain) GenerateVerificationCode(codeGenerator crypto.Generator } func NewIAMDomainName(orgName, iamDomain string) string { - return strings.ToLower(strings.ReplaceAll(strings.TrimSpace(orgName), " ", "-") + "." + iamDomain) + // Reference: label domain requirements https://www.nic.ad.jp/timeline/en/20th/appendix1.html + + // Replaces spaces in org name with hyphens + label := strings.ReplaceAll(orgName, " ", "-") + + // The label must only contains alphanumeric characters and hyphens + // Invalid characters are replaced with and empty space + label = string(regexp.MustCompile(`[^a-zA-Z0-9-]`).ReplaceAll([]byte(label), []byte(""))) + + // The label cannot exceed 63 characters + if len(label) > 63 { + label = label[:63] + } + + // The total length of the resulting domain can't exceed 253 characters + domain := label + "." + iamDomain + if len(domain) > 253 { + truncateNChars := len(domain) - 253 + label = label[:len(label)-truncateNChars] + } + + // Label (maybe truncated) can't start with a hyphen + if len(label) > 0 && label[0:1] == "-" { + label = label[1:] + } + + // Label (maybe truncated) can't end with a hyphen + if len(label) > 0 && label[len(label)-1:] == "-" { + label = label[:len(label)-1] + } + + return strings.ToLower(label + "." + iamDomain) } type OrgDomainValidationType int32 diff --git a/internal/domain/org_domain_test.go b/internal/domain/org_domain_test.go new file mode 100644 index 000000000..8dd77ca32 --- /dev/null +++ b/internal/domain/org_domain_test.go @@ -0,0 +1,90 @@ +package domain + +import ( + "testing" +) + +func TestNewIAMDomainName(t *testing.T) { + type args struct { + orgName string + iamDomain string + } + tests := []struct { + name string + args args + result string + }{ + { + name: "Single word domain is already valid", + args: args{ + orgName: "single-word-domain", + iamDomain: "localhost", + }, + result: "single-word-domain.localhost", + }, + { + name: "resulting domain should be in lowercase", + args: args{ + orgName: "Uppercase org Name", + iamDomain: "localhost", + }, + result: "uppercase-org-name.localhost", + }, + { + name: "replace spaces with hyphens", + args: args{ + orgName: "my org name", + iamDomain: "localhost", + }, + result: "my-org-name.localhost", + }, + { + name: "replace invalid characters [^a-zA-Z0-9-] with empty spaces", + args: args{ + orgName: "mí Örg name?", + iamDomain: "localhost", + }, + result: "m-rg-name.localhost", + }, + { + name: "label created from org name size is not greater than 63 chars", + args: args{ + orgName: "my organization name must not exceed sixty-three characters 1234", + iamDomain: "localhost", + }, + result: "my-organization-name-must-not-exceed-sixty-three-characters-123.localhost", + }, + { + name: "resulting domain cannot exceed 253 chars", + args: args{ + orgName: "Lorem ipsum dolor sit amet", + iamDomain: "llgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk", + }, + result: "lorem-ipsum-dolor-sit.llgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk", + }, + { + name: "label based on org name should not end with a hyphen", + args: args{ + orgName: "my super long organization name with many many many characters ", + iamDomain: "localhost", + }, + result: "my-super-long-organization-name-with-many-many-many-characters.localhost", + }, + { + name: "label based on org name should not start with a hyphen", + args: args{ + orgName: " my super long organization name with many many many characters", + iamDomain: "localhost", + }, + result: "my-super-long-organization-name-with-many-many-many-characters.localhost", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + domain := NewIAMDomainName(tt.args.orgName, tt.args.iamDomain) + if tt.result != domain { + t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, domain) + } + }) + } +} diff --git a/internal/domain/policy_login.go b/internal/domain/policy_login.go index b9c169193..c898ea254 100644 --- a/internal/domain/policy_login.go +++ b/internal/domain/policy_login.go @@ -16,6 +16,7 @@ type LoginPolicy struct { AllowExternalIDP bool IDPProviders []*IDPProvider ForceMFA bool + ForceMFALocalOnly bool SecondFactors []SecondFactorType MultiFactors []MultiFactorType PasswordlessType PasswordlessType diff --git a/internal/domain/user.go b/internal/domain/user.go index a5e01361f..b46d4227d 100644 --- a/internal/domain/user.go +++ b/internal/domain/user.go @@ -60,6 +60,41 @@ func (f UserAuthMethodType) Valid() bool { return f >= 0 && f < userAuthMethodTypeCount } +// HasMFA checks whether the user authenticated with multiple auth factors. +// This can either be true if the list contains a [UserAuthMethodType] which by itself is MFA (e.g. [UserAuthMethodTypePasswordless]) +// or if multiple factors were used (e.g. [UserAuthMethodTypePassword] and [UserAuthMethodTypeU2F]) +func HasMFA(methods []UserAuthMethodType) bool { + var factors int + for _, method := range methods { + switch method { + case UserAuthMethodTypePassword: + factors++ + case UserAuthMethodTypePasswordless: + return true + case UserAuthMethodTypeU2F: + factors++ + case UserAuthMethodTypeOTP: + factors++ + case UserAuthMethodTypeIDP: + factors++ + case UserAuthMethodTypeUnspecified, + userAuthMethodTypeCount: + // ignore + } + } + return factors > 1 +} + +// RequiresMFA checks whether the user requires to authenticate with multiple auth factors based on the LoginPolicy and the authentication type. +// Internal authentication will require MFA if either option is activated. +// External authentication will only require MFA if it's forced generally and not local only. +func RequiresMFA(forceMFA, forceMFALocalOnly, isInternalLogin bool) bool { + if isInternalLogin { + return forceMFA || forceMFALocalOnly + } + return forceMFA && !forceMFALocalOnly +} + type PersonalAccessTokenState int32 const ( diff --git a/internal/eventstore/handler/crdb/handler_stmt.go b/internal/eventstore/handler/crdb/handler_stmt.go index 8f6d9481f..e49fe007b 100644 --- a/internal/eventstore/handler/crdb/handler_stmt.go +++ b/internal/eventstore/handler/crdb/handler_stmt.go @@ -11,6 +11,7 @@ import ( "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" + "github.com/zitadel/zitadel/internal/repository/pseudo" ) var ( @@ -49,6 +50,8 @@ type StatementHandler struct { initialized chan bool bulkLimit uint64 + + reduceScheduledPseudoEvent bool } func NewStatementHandler( @@ -57,30 +60,40 @@ func NewStatementHandler( ) StatementHandler { aggregateTypes := make([]eventstore.AggregateType, 0, len(config.Reducers)) reduces := make(map[eventstore.EventType]handler.Reduce, len(config.Reducers)) + reduceScheduledPseudoEvent := false for _, aggReducer := range config.Reducers { aggregateTypes = append(aggregateTypes, aggReducer.Aggregate) + if aggReducer.Aggregate == pseudo.AggregateType { + reduceScheduledPseudoEvent = true + if len(config.Reducers) != 1 || + len(aggReducer.EventRedusers) != 1 || + aggReducer.EventRedusers[0].Event != pseudo.ScheduledEventType { + panic("if a pseudo.AggregateType is reduced, exactly one event reducer for pseudo.ScheduledEventType is supported and no other aggregate can be reduced") + } + } for _, eventReducer := range aggReducer.EventRedusers { reduces[eventReducer.Event] = eventReducer.Reduce } } h := StatementHandler{ - client: config.Client, - sequenceTable: config.SequenceTable, - maxFailureCount: config.MaxFailureCount, - currentSequenceStmt: fmt.Sprintf(currentSequenceStmtFormat, config.SequenceTable), - updateSequencesBaseStmt: fmt.Sprintf(updateCurrentSequencesStmtFormat, config.SequenceTable), - failureCountStmt: fmt.Sprintf(failureCountStmtFormat, config.FailedEventsTable), - setFailureCountStmt: fmt.Sprintf(setFailureCountStmtFormat, config.FailedEventsTable), - aggregates: aggregateTypes, - reduces: reduces, - bulkLimit: config.BulkLimit, - Locker: NewLocker(config.Client.DB, config.LockTable, config.ProjectionName), - initCheck: config.InitCheck, - initialized: make(chan bool), + client: config.Client, + sequenceTable: config.SequenceTable, + maxFailureCount: config.MaxFailureCount, + currentSequenceStmt: fmt.Sprintf(currentSequenceStmtFormat, config.SequenceTable), + updateSequencesBaseStmt: fmt.Sprintf(updateCurrentSequencesStmtFormat, config.SequenceTable), + failureCountStmt: fmt.Sprintf(failureCountStmtFormat, config.FailedEventsTable), + setFailureCountStmt: fmt.Sprintf(setFailureCountStmtFormat, config.FailedEventsTable), + aggregates: aggregateTypes, + reduces: reduces, + bulkLimit: config.BulkLimit, + Locker: NewLocker(config.Client.DB, config.LockTable, config.ProjectionName), + initCheck: config.InitCheck, + initialized: make(chan bool), + reduceScheduledPseudoEvent: reduceScheduledPseudoEvent, } - h.ProjectionHandler = handler.NewProjectionHandler(ctx, config.ProjectionHandlerConfig, h.reduce, h.Update, h.SearchQuery, h.Lock, h.Unlock, h.initialized) + h.ProjectionHandler = handler.NewProjectionHandler(ctx, config.ProjectionHandlerConfig, h.reduce, h.Update, h.searchQuery, h.Lock, h.Unlock, h.initialized, reduceScheduledPseudoEvent) return h } @@ -88,10 +101,19 @@ func NewStatementHandler( func (h *StatementHandler) Start() { h.initialized <- true close(h.initialized) - h.Subscribe(h.aggregates...) + if !h.reduceScheduledPseudoEvent { + h.Subscribe(h.aggregates...) + } } -func (h *StatementHandler) SearchQuery(ctx context.Context, instanceIDs []string) (*eventstore.SearchQueryBuilder, uint64, error) { +func (h *StatementHandler) searchQuery(ctx context.Context, instanceIDs []string) (*eventstore.SearchQueryBuilder, uint64, error) { + if h.reduceScheduledPseudoEvent { + return nil, 1, nil + } + return h.dbSearchQuery(ctx, instanceIDs) +} + +func (h *StatementHandler) dbSearchQuery(ctx context.Context, instanceIDs []string) (*eventstore.SearchQueryBuilder, uint64, error) { sequences, err := h.currentSequences(ctx, h.client.QueryContext, instanceIDs) if err != nil { return nil, 0, err @@ -115,7 +137,6 @@ func (h *StatementHandler) SearchQuery(ctx context.Context, instanceIDs []string InstanceID(instanceID) } } - return queryBuilder, h.bulkLimit, nil } diff --git a/internal/eventstore/handler/crdb/handler_stmt_test.go b/internal/eventstore/handler/crdb/handler_stmt_test.go index 8c0d1537f..b72db40eb 100644 --- a/internal/eventstore/handler/crdb/handler_stmt_test.go +++ b/internal/eventstore/handler/crdb/handler_stmt_test.go @@ -18,6 +18,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/repository" es_repo_mock "github.com/zitadel/zitadel/internal/eventstore/repository/mock" "github.com/zitadel/zitadel/internal/id" + "github.com/zitadel/zitadel/internal/repository/pseudo" ) var ( @@ -60,7 +61,7 @@ func TestProjectionHandler_SearchQuery(t *testing.T) { type fields struct { sequenceTable string projectionName string - aggregates []eventstore.AggregateType + reducers []handler.AggregateReducer bulkLimit uint64 } type args struct { @@ -77,7 +78,7 @@ func TestProjectionHandler_SearchQuery(t *testing.T) { fields: fields{ sequenceTable: "my_sequences", projectionName: "my_projection", - aggregates: []eventstore.AggregateType{"testAgg"}, + reducers: failingAggregateReducers("testAgg"), bulkLimit: 5, }, args: args{ @@ -99,7 +100,7 @@ func TestProjectionHandler_SearchQuery(t *testing.T) { fields: fields{ sequenceTable: "my_sequences", projectionName: "my_projection", - aggregates: []eventstore.AggregateType{"testAgg"}, + reducers: failingAggregateReducers("testAgg"), bulkLimit: 5, }, args: args{ @@ -129,7 +130,7 @@ func TestProjectionHandler_SearchQuery(t *testing.T) { fields: fields{ sequenceTable: "my_sequences", projectionName: "my_projection", - aggregates: []eventstore.AggregateType{"testAgg"}, + reducers: failingAggregateReducers("testAgg"), bulkLimit: 5, }, args: args{ @@ -158,6 +159,32 @@ func TestProjectionHandler_SearchQuery(t *testing.T) { Limit(5), }, }, + { + name: "scheduled pseudo event", + fields: fields{ + sequenceTable: "my_sequences", + projectionName: "my_projection", + reducers: []handler.AggregateReducer{{ + Aggregate: pseudo.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: pseudo.ScheduledEventType, + Reduce: testReduceErr(errors.New("should not be called")), + }, + }, + }}, + bulkLimit: 5, + }, + args: args{ + instanceIDs: []string{"instanceID1", "instanceID2"}, + }, + want: want{ + limit: 1, + isErr: func(err error) bool { + return err == nil + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -177,15 +204,14 @@ func TestProjectionHandler_SearchQuery(t *testing.T) { Client: &database.DB{ DB: client, }, + Reducers: tt.fields.reducers, }) - h.aggregates = tt.fields.aggregates - for _, expectation := range tt.want.expectations { expectation(mock) } - query, limit, err := h.SearchQuery(context.Background(), tt.args.instanceIDs) + query, limit, err := h.searchQuery(context.Background(), tt.args.instanceIDs) if !tt.want.isErr(err) { t.Errorf("ProjectionHandler.prepareBulkStmts() error = %v", err) return @@ -1768,3 +1794,17 @@ func testReduceErr(err error) handler.Reduce { return nil, err } } + +func failingAggregateReducers(aggregates ...eventstore.AggregateType) []handler.AggregateReducer { + reducers := make([]handler.AggregateReducer, len(aggregates)) + for idx := range aggregates { + reducers[idx] = handler.AggregateReducer{ + Aggregate: aggregates[idx], + EventRedusers: []handler.EventReducer{{ + Event: "any.event", + Reduce: testReduceErr(errors.New("should not be called")), + }}, + } + } + return reducers +} diff --git a/internal/eventstore/handler/crdb/statement.go b/internal/eventstore/handler/crdb/statement.go index 591751e66..efcc4952e 100644 --- a/internal/eventstore/handler/crdb/statement.go +++ b/internal/eventstore/handler/crdb/statement.go @@ -235,12 +235,6 @@ func AddDeleteStatement(conditions []handler.Condition, opts ...execOption) func } } -func AddCopyStatement(conflict, from, to []handler.Column, conditions []handler.Condition, opts ...execOption) func(eventstore.Event) Exec { - return func(event eventstore.Event) Exec { - return NewCopyStatement(event, conflict, from, to, conditions, opts...).Execute - } -} - func NewArrayAppendCol(column string, value interface{}) handler.Column { return handler.Column{ Name: column, @@ -286,12 +280,30 @@ func NewCopyCol(column, from string) handler.Column { } func NewLessThanCond(column string, value interface{}) handler.Condition { - return handler.Condition{ - Name: column, - Value: value, - ParameterOpt: func(placeholder string) string { - return " < " + placeholder - }, + return func(param string) (string, interface{}) { + return column + " < " + param, value + } +} + +func NewIsNullCond(column string) handler.Condition { + return func(param string) (string, interface{}) { + return column + " IS NULL", nil + } +} + +// NewTextArrayContainsCond returns a handler.Condition that checks if the column that stores an array of text contains the given value +func NewTextArrayContainsCond(column string, value string) handler.Condition { + return func(param string) (string, interface{}) { + return column + " @> " + param, database.StringArray{value} + } +} + +// Not is a function and not a method, so that calling it is well readable +// For example conditions := []handler.Condition{ Not(NewTextArrayContainsCond())} +func Not(condition handler.Condition) handler.Condition { + return func(param string) (string, interface{}) { + cond, value := condition(param) + return "NOT (" + cond + ")", value } } @@ -300,7 +312,7 @@ func NewLessThanCond(column string, value interface{}) handler.Condition { // if the value of a col is empty the data will be copied from the selected row // if the value of a col is not empty the data will be set by the static value // conds represent the conditions for the selection subquery -func NewCopyStatement(event eventstore.Event, conflictCols, from, to []handler.Column, conds []handler.Condition, opts ...execOption) *handler.Statement { +func NewCopyStatement(event eventstore.Event, conflictCols, from, to []handler.Column, nsCond []handler.NamespacedCondition, opts ...execOption) *handler.Statement { columnNames := make([]string, len(to)) selectColumns := make([]string, len(from)) updateColumns := make([]string, len(columnNames)) @@ -319,13 +331,12 @@ func NewCopyStatement(event eventstore.Event, conflictCols, from, to []handler.C } } - - wheres := make([]string, len(conds)) - for i, cond := range conds { - argCounter++ - wheres[i] = "copy_table." + cond.Name + " = $" + strconv.Itoa(argCounter) - args = append(args, cond.Value) + cond := make([]handler.Condition, len(nsCond)) + for i := range nsCond { + cond[i] = nsCond[i]("copy_table") } + wheres, values := conditionsToWhere(cond, len(args)) + args = append(args, values...) conflictTargets := make([]string, len(conflictCols)) for i, conflictCol := range conflictCols { @@ -340,7 +351,7 @@ func NewCopyStatement(event eventstore.Event, conflictCols, from, to []handler.C config.err = handler.ErrNoValues } - if len(conds) == 0 { + if len(cond) == 0 { config.err = handler.ErrNoCondition } @@ -394,18 +405,16 @@ func columnsToQuery(cols []handler.Column) (names []string, parameters []string, return names, parameters, values[:parameterIndex] } -func conditionsToWhere(cols []handler.Condition, paramOffset int) (wheres []string, values []interface{}) { - wheres = make([]string, len(cols)) - values = make([]interface{}, len(cols)) - - for i, col := range cols { - wheres[i] = "(" + col.Name + " = $" + strconv.Itoa(i+1+paramOffset) + ")" - if col.ParameterOpt != nil { - wheres[i] = "(" + col.Name + col.ParameterOpt("$"+strconv.Itoa(i+1+paramOffset)) + ")" +func conditionsToWhere(conditions []handler.Condition, paramOffset int) (wheres []string, values []interface{}) { + wheres = make([]string, len(conditions)) + values = make([]interface{}, 0, len(conditions)) + for i, conditionFunc := range conditions { + condition, value := conditionFunc("$" + strconv.Itoa(i+1+paramOffset)) + wheres[i] = "(" + condition + ")" + if value != nil { + values = append(values, value) } - values[i] = col.Value } - return wheres, values } diff --git a/internal/eventstore/handler/crdb/statement_test.go b/internal/eventstore/handler/crdb/statement_test.go index fd9f451d9..e023f0079 100644 --- a/internal/eventstore/handler/crdb/statement_test.go +++ b/internal/eventstore/handler/crdb/statement_test.go @@ -6,6 +6,7 @@ import ( "reflect" "testing" + "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" ) @@ -420,10 +421,7 @@ func TestNewUpdateStatement(t *testing.T) { }, }, conditions: []handler.Condition{ - { - Name: "col2", - Value: 1, - }, + handler.NewCond("col2", 1), }, }, want: want{ @@ -450,10 +448,7 @@ func TestNewUpdateStatement(t *testing.T) { }, values: []handler.Column{}, conditions: []handler.Condition{ - { - Name: "col2", - Value: 1, - }, + handler.NewCond("col2", 1), }, }, want: want{ @@ -515,10 +510,7 @@ func TestNewUpdateStatement(t *testing.T) { }, }, conditions: []handler.Condition{ - { - Name: "col2", - Value: 1, - }, + handler.NewCond("col2", 1), }, }, want: want{ @@ -560,10 +552,7 @@ func TestNewUpdateStatement(t *testing.T) { }, }, conditions: []handler.Condition{ - { - Name: "col2", - Value: 1, - }, + handler.NewCond("col2", 1), }, }, want: want{ @@ -630,10 +619,7 @@ func TestNewDeleteStatement(t *testing.T) { previousSequence: 0, }, conditions: []handler.Condition{ - { - Name: "col2", - Value: 1, - }, + handler.NewCond("col2", 1), }, }, want: want{ @@ -683,10 +669,7 @@ func TestNewDeleteStatement(t *testing.T) { aggregateType: "agg", }, conditions: []handler.Condition{ - { - Name: "col1", - Value: 1, - }, + handler.NewCond("col1", 1), }, }, want: want{ @@ -842,11 +825,9 @@ func TestNewMultiStatement(t *testing.T) { execs: []func(eventstore.Event) Exec{ AddDeleteStatement( []handler.Condition{ - { - Name: "col1", - Value: 1, - }, - }), + handler.NewCond("col1", 1), + }, + ), AddCreateStatement( []handler.Column{ { @@ -876,11 +857,9 @@ func TestNewMultiStatement(t *testing.T) { }, }, []handler.Condition{ - { - Name: "col1", - Value: 1, - }, - }), + handler.NewCond("col1", 1), + }, + ), }, }, want: want{ @@ -942,7 +921,7 @@ func TestNewCopyStatement(t *testing.T) { conflictingCols []handler.Column from []handler.Column to []handler.Column - conds []handler.Condition + conds []handler.NamespacedCondition } type want struct { aggregateType eventstore.AggregateType @@ -966,11 +945,8 @@ func TestNewCopyStatement(t *testing.T) { sequence: 1, previousSequence: 0, }, - conds: []handler.Condition{ - { - Name: "col2", - Value: 1, - }, + conds: []handler.NamespacedCondition{ + handler.NewNamespacedCondition("col2", 1), }, }, want: want{ @@ -995,7 +971,7 @@ func TestNewCopyStatement(t *testing.T) { sequence: 1, previousSequence: 0, }, - conds: []handler.Condition{}, + conds: []handler.NamespacedCondition{}, from: []handler.Column{ { Name: "col", @@ -1029,7 +1005,7 @@ func TestNewCopyStatement(t *testing.T) { sequence: 1, previousSequence: 0, }, - conds: []handler.Condition{}, + conds: []handler.NamespacedCondition{}, from: []handler.Column{ { Name: "col", @@ -1066,10 +1042,8 @@ func TestNewCopyStatement(t *testing.T) { sequence: 1, previousSequence: 0, }, - conds: []handler.Condition{ - { - Name: "col", - }, + conds: []handler.NamespacedCondition{ + handler.NewNamespacedCondition("col2", nil), }, from: []handler.Column{}, }, @@ -1124,15 +1098,9 @@ func TestNewCopyStatement(t *testing.T) { Name: "col_b", }, }, - conds: []handler.Condition{ - { - Name: "id", - Value: 2, - }, - { - Name: "state", - Value: 3, - }, + conds: []handler.NamespacedCondition{ + handler.NewNamespacedCondition("id", 2), + handler.NewNamespacedCondition("state", 3), }, }, want: want{ @@ -1143,7 +1111,7 @@ func TestNewCopyStatement(t *testing.T) { executer: &wantExecuter{ params: []params{ { - query: "INSERT INTO my_table (state, id, col_a, col_b) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE copy_table.id = $2 AND copy_table.state = $3 ON CONFLICT () DO UPDATE SET (state, id, col_a, col_b) = ($1, EXCLUDED.id, EXCLUDED.col_a, EXCLUDED.col_b)", + query: "INSERT INTO my_table (state, id, col_a, col_b) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE (copy_table.id = $2) AND (copy_table.state = $3) ON CONFLICT () DO UPDATE SET (state, id, col_a, col_b) = ($1, EXCLUDED.id, EXCLUDED.col_a, EXCLUDED.col_b)", args: []interface{}{1, 2, 3}, }, }, @@ -1191,15 +1159,9 @@ func TestNewCopyStatement(t *testing.T) { Name: "col_d", }, }, - conds: []handler.Condition{ - { - Name: "id", - Value: 2, - }, - { - Name: "state", - Value: 3, - }, + conds: []handler.NamespacedCondition{ + handler.NewNamespacedCondition("id", 2), + handler.NewNamespacedCondition("state", 3), }, }, want: want{ @@ -1210,7 +1172,7 @@ func TestNewCopyStatement(t *testing.T) { executer: &wantExecuter{ params: []params{ { - query: "INSERT INTO my_table (state, id, col_c, col_d) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE copy_table.id = $2 AND copy_table.state = $3 ON CONFLICT () DO UPDATE SET (state, id, col_c, col_d) = ($1, EXCLUDED.id, EXCLUDED.col_a, EXCLUDED.col_b)", + query: "INSERT INTO my_table (state, id, col_c, col_d) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE (copy_table.id = $2) AND (copy_table.state = $3) ON CONFLICT () DO UPDATE SET (state, id, col_c, col_d) = ($1, EXCLUDED.id, EXCLUDED.col_a, EXCLUDED.col_b)", args: []interface{}{1, 2, 3}, }, }, @@ -1395,7 +1357,7 @@ func Test_columnsToQuery(t *testing.T) { } } -func Test_columnsToWhere(t *testing.T) { +func Test_conditionsToWhere(t *testing.T) { type args struct { conds []handler.Condition paramOffset int @@ -1421,10 +1383,7 @@ func Test_columnsToWhere(t *testing.T) { name: "no offset", args: args{ conds: []handler.Condition{ - { - Name: "col1", - Value: "val1", - }, + handler.NewCond("col1", "val1"), }, paramOffset: 0, }, @@ -1437,14 +1396,8 @@ func Test_columnsToWhere(t *testing.T) { name: "multiple cols", args: args{ conds: []handler.Condition{ - { - Name: "col1", - Value: "val1", - }, - { - Name: "col2", - Value: "val2", - }, + handler.NewCond("col1", "val1"), + handler.NewCond("col2", "val2"), }, paramOffset: 0, }, @@ -1457,10 +1410,7 @@ func Test_columnsToWhere(t *testing.T) { name: "2 offset", args: args{ conds: []handler.Condition{ - { - Name: "col1", - Value: "val1", - }, + handler.NewCond("col1", "val1"), }, paramOffset: 2, }, @@ -1469,6 +1419,54 @@ func Test_columnsToWhere(t *testing.T) { values: []interface{}{"val1"}, }, }, + { + name: "less than", + args: args{ + conds: []handler.Condition{ + NewLessThanCond("col1", "val1"), + }, + }, + want: want{ + wheres: []string{"(col1 < $1)"}, + values: []interface{}{"val1"}, + }, + }, + { + name: "is null", + args: args{ + conds: []handler.Condition{ + NewIsNullCond("col1"), + }, + }, + want: want{ + wheres: []string{"(col1 IS NULL)"}, + values: []interface{}{}, + }, + }, + { + name: "text array contains", + args: args{ + conds: []handler.Condition{ + NewTextArrayContainsCond("col1", "val1"), + }, + }, + want: want{ + wheres: []string{"(col1 @> $1)"}, + values: []interface{}{database.StringArray{"val1"}}, + }, + }, + { + name: "not", + args: args{ + conds: []handler.Condition{ + Not(handler.NewCond("col1", "val1")), + }, + }, + want: want{ + wheres: []string{"(NOT (col1 = $1))"}, + values: []interface{}{"val1"}, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/eventstore/handler/handler_projection.go b/internal/eventstore/handler/handler_projection.go index 808da1dbb..baab2d3a6 100644 --- a/internal/eventstore/handler/handler_projection.go +++ b/internal/eventstore/handler/handler_projection.go @@ -6,10 +6,13 @@ import ( "runtime/debug" "time" + "github.com/sirupsen/logrus" "github.com/zitadel/logging" "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/call" "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/pseudo" ) const ( @@ -49,19 +52,20 @@ type NowFunc func() time.Time type ProjectionHandler struct { Handler - ProjectionName string - reduce Reduce - update Update - searchQuery SearchQuery - triggerProjection *time.Timer - lock Lock - unlock Unlock - requeueAfter time.Duration - retryFailedAfter time.Duration - retries int - concurrentInstances int - handleActiveInstances time.Duration - nowFunc NowFunc + ProjectionName string + reduce Reduce + update Update + searchQuery SearchQuery + triggerProjection *time.Timer + lock Lock + unlock Unlock + requeueAfter time.Duration + retryFailedAfter time.Duration + retries int + concurrentInstances int + handleActiveInstances time.Duration + nowFunc NowFunc + reduceScheduledPseudoEvent bool } func NewProjectionHandler( @@ -73,59 +77,86 @@ func NewProjectionHandler( lock Lock, unlock Unlock, initialized <-chan bool, + reduceScheduledPseudoEvent bool, ) *ProjectionHandler { concurrentInstances := int(config.ConcurrentInstances) if concurrentInstances < 1 { concurrentInstances = 1 } h := &ProjectionHandler{ - Handler: NewHandler(config.HandlerConfig), - ProjectionName: config.ProjectionName, - reduce: reduce, - update: update, - searchQuery: query, - lock: lock, - unlock: unlock, - requeueAfter: config.RequeueEvery, - triggerProjection: time.NewTimer(0), // first trigger is instant on startup - retryFailedAfter: config.RetryFailedAfter, - retries: int(config.Retries), - concurrentInstances: concurrentInstances, - handleActiveInstances: config.HandleActiveInstances, - nowFunc: time.Now, + Handler: NewHandler(config.HandlerConfig), + ProjectionName: config.ProjectionName, + reduce: reduce, + update: update, + searchQuery: query, + lock: lock, + unlock: unlock, + requeueAfter: config.RequeueEvery, + triggerProjection: time.NewTimer(0), // first trigger is instant on startup + retryFailedAfter: config.RetryFailedAfter, + retries: int(config.Retries), + concurrentInstances: concurrentInstances, + handleActiveInstances: config.HandleActiveInstances, + nowFunc: time.Now, + reduceScheduledPseudoEvent: reduceScheduledPseudoEvent, } go func() { <-initialized - go h.subscribe(ctx) - + if !h.reduceScheduledPseudoEvent { + go h.subscribe(ctx) + } go h.schedule(ctx) }() return h } -// Trigger handles all events for the provided instances (or current instance from context if non specified) -// by calling FetchEvents and Process until the amount of events is smaller than the BulkLimit -func (h *ProjectionHandler) Trigger(ctx context.Context, instances ...string) error { - ids := []string{authz.GetInstance(ctx).InstanceID()} - if len(instances) > 0 { - ids = instances +func triggerInstances(ctx context.Context, instances []string) []string { + if len(instances) == 0 { + instances = append(instances, authz.GetInstance(ctx).InstanceID()) } + return instances +} + +// Trigger handles all events for the provided instances (or current instance from context if non specified) +// by calling FetchEvents and Process until the amount of events is smaller than the BulkLimit. +// If a bulk action was executed, the call timestamp in context will be reset for subsequent queries. +// The returned context is never nil. It is either the original context or an updated context. +// +// If Trigger encounters an error, it is only logged. If the error is important for the caller, +// use TriggerErr instead. +func (h *ProjectionHandler) Trigger(ctx context.Context, instances ...string) context.Context { + instances = triggerInstances(ctx, instances) + ctx, err := h.TriggerErr(ctx, instances...) + logging.OnError(err).WithFields(logrus.Fields{ + "projection": h.ProjectionName, + "instanceIDs": instances, + }).Error("trigger failed") + return ctx +} + +// TriggerErr handles all events for the provided instances (or current instance from context if non specified) +// by calling FetchEvents and Process until the amount of events is smaller than the BulkLimit. +// If a bulk action was executed, the call timestamp in context will be reset for subsequent queries. +// The returned context is never nil. It is either the original context or an updated context. +func (h *ProjectionHandler) TriggerErr(ctx context.Context, instances ...string) (context.Context, error) { + instances = triggerInstances(ctx, instances) for { - events, hasLimitExceeded, err := h.FetchEvents(ctx, ids...) + events, hasLimitExceeded, err := h.FetchEvents(ctx, instances...) if err != nil { - return err + return ctx, err } if len(events) == 0 { - return nil + return ctx, nil } _, err = h.Process(ctx, events...) + ctx = call.ResetTimestamp(ctx) if err != nil { - return err + return ctx, err } if !hasLimitExceeded { - return nil + return ctx, nil } } } @@ -158,6 +189,13 @@ func (h *ProjectionHandler) Process(ctx context.Context, events ...eventstore.Ev // FetchEvents checks the current sequences and filters for newer events func (h *ProjectionHandler) FetchEvents(ctx context.Context, instances ...string) ([]eventstore.Event, bool, error) { + if h.reduceScheduledPseudoEvent { + return h.fetchPseudoEvents(ctx, instances...) + } + return h.fetchDBEvents(ctx, instances...) +} + +func (h *ProjectionHandler) fetchDBEvents(ctx context.Context, instances ...string) ([]eventstore.Event, bool, error) { eventQuery, eventsLimit, err := h.searchQuery(ctx, instances) if err != nil { return nil, false, err @@ -169,6 +207,10 @@ func (h *ProjectionHandler) FetchEvents(ctx context.Context, instances ...string return events, int(eventsLimit) == len(events), err } +func (h *ProjectionHandler) fetchPseudoEvents(ctx context.Context, instances ...string) ([]eventstore.Event, bool, error) { + return []eventstore.Event{pseudo.NewScheduledEvent(ctx, time.Now(), instances...)}, false, nil +} + func (h *ProjectionHandler) subscribe(ctx context.Context) { ctx, cancel := context.WithCancel(ctx) defer func() { @@ -258,7 +300,7 @@ func (h *ProjectionHandler) schedule(ctx context.Context) { continue } go h.cancelOnErr(lockInstanceCtx, errs, cancelInstanceLock) - err = h.Trigger(lockInstanceCtx, instances...) + _, err = h.TriggerErr(lockInstanceCtx, instances...) if err != nil { logging.WithFields("projection", h.ProjectionName, "instanceIDs", instances).WithError(err).Error("trigger failed") failed = true diff --git a/internal/eventstore/handler/handler_projection_test.go b/internal/eventstore/handler/handler_projection_test.go index 3ab88ef4a..3ee791a2d 100644 --- a/internal/eventstore/handler/handler_projection_test.go +++ b/internal/eventstore/handler/handler_projection_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/call" "github.com/zitadel/zitadel/internal/api/service" "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/eventstore" @@ -29,6 +30,47 @@ var ( ) func TestProjectionHandler_Trigger(t *testing.T) { + const pause = time.Millisecond + + startCtx := call.WithTimestamp(context.Background()) + start := call.FromContext(startCtx) + + h := &ProjectionHandler{ + Handler: Handler{ + Eventstore: eventstore.NewEventstore(eventstore.TestConfig( + es_repo_mock.NewRepo(t).ExpectFilterEvents( + &repository.Event{ + ID: "id", + Sequence: 1, + PreviousAggregateSequence: 0, + CreationDate: time.Now(), + Type: "test.added", + Version: "v1", + AggregateID: "testid", + AggregateType: "testAgg", + }, + ), + )), + }, + ProjectionName: "test", + reduce: testReduce(newTestStatement("testAgg", 1, 0)), + update: testUpdate(t, 1, 0, nil), + searchQuery: testQuery( + eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AddQuery(). + AggregateTypes("test"). + Builder(), + 5, nil, + ), + } + + time.Sleep(pause) + endCtx := h.Trigger(startCtx) + // check if the new context has a call timestamp that's later than start+pause. + assert.WithinRange(t, call.FromContext(endCtx), start.Add(pause), start.Add(pause+time.Second)) +} + +func TestProjectionHandler_TriggerErr(t *testing.T) { type fields struct { reduce Reduce update Update @@ -223,7 +265,8 @@ func TestProjectionHandler_Trigger(t *testing.T) { searchQuery: tt.fields.query, } - err := h.Trigger(tt.args.ctx, tt.args.instances...) + // context timestamp is checked in [TestProjectionHandler_Trigger] + _, err := h.TriggerErr(tt.args.ctx, tt.args.instances...) if !tt.want.isErr(err) { t.Errorf("unexpected error %v", err) } @@ -342,6 +385,7 @@ func TestProjectionHandler_Process(t *testing.T) { nil, nil, nil, + false, ) index, err := h.Process(tt.args.ctx, tt.args.events...) diff --git a/internal/eventstore/handler/statement.go b/internal/eventstore/handler/statement.go index ae7bec92e..1eecd78f2 100644 --- a/internal/eventstore/handler/statement.go +++ b/internal/eventstore/handler/statement.go @@ -4,7 +4,6 @@ import ( "database/sql" "encoding/json" "errors" - "github.com/zitadel/logging" "github.com/zitadel/zitadel/internal/eventstore" @@ -62,11 +61,18 @@ func NewJSONCol(name string, value interface{}) Column { return NewCol(name, marshalled) } -type Condition Column +type Condition func(param string) (string, interface{}) + +type NamespacedCondition func(namespace string) Condition func NewCond(name string, value interface{}) Condition { - return Condition{ - Name: name, - Value: value, + return func(param string) (string, interface{}) { + return name + " = " + param, value + } +} + +func NewNamespacedCondition(name string, value interface{}) NamespacedCondition { + return func(namespace string) Condition { + return NewCond(namespace+"."+name, value) } } diff --git a/internal/integration/client.go b/internal/integration/client.go index 86b78bb87..65e0e9ab1 100644 --- a/internal/integration/client.go +++ b/internal/integration/client.go @@ -17,9 +17,12 @@ import ( openid "github.com/zitadel/zitadel/internal/idp/providers/oidc" "github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/pkg/grpc/admin" + "github.com/zitadel/zitadel/pkg/grpc/auth" mgmt "github.com/zitadel/zitadel/pkg/grpc/management" object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha" + oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" session "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha" + "github.com/zitadel/zitadel/pkg/grpc/system" user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha" ) @@ -27,8 +30,11 @@ type Client struct { CC *grpc.ClientConn Admin admin.AdminServiceClient Mgmt mgmt.ManagementServiceClient + Auth auth.AuthServiceClient UserV2 user.UserServiceClient SessionV2 session.SessionServiceClient + OIDCv2 oidc_pb.OIDCServiceClient + System system.SystemServiceClient } func newClient(cc *grpc.ClientConn) Client { @@ -36,11 +42,38 @@ func newClient(cc *grpc.ClientConn) Client { CC: cc, Admin: admin.NewAdminServiceClient(cc), Mgmt: mgmt.NewManagementServiceClient(cc), + Auth: auth.NewAuthServiceClient(cc), UserV2: user.NewUserServiceClient(cc), SessionV2: session.NewSessionServiceClient(cc), + OIDCv2: oidc_pb.NewOIDCServiceClient(cc), + System: system.NewSystemServiceClient(cc), } } +func (t *Tester) UseIsolatedInstance(iamOwnerCtx, systemCtx context.Context) (primaryDomain, instanceId string, authenticatedIamOwnerCtx context.Context) { + primaryDomain = randString(5) + ".integration" + instance, err := t.Client.System.CreateInstance(systemCtx, &system.CreateInstanceRequest{ + InstanceName: "testinstance", + CustomDomain: primaryDomain, + Owner: &system.CreateInstanceRequest_Machine_{ + Machine: &system.CreateInstanceRequest_Machine{ + UserName: "owner", + Name: "owner", + PersonalAccessToken: &system.CreateInstanceRequest_PersonalAccessToken{}, + }, + }, + }) + if err != nil { + panic(err) + } + t.createClientConn(iamOwnerCtx, grpc.WithAuthority(primaryDomain)) + instanceId = instance.GetInstanceId() + t.Users.Set(instanceId, IAMOwner, &User{ + Token: instance.GetPat(), + }) + return primaryDomain, instanceId, t.WithInstanceAuthorization(iamOwnerCtx, IAMOwner, instanceId) +} + func (s *Tester) CreateHumanUser(ctx context.Context) *user.AddHumanUserResponse { resp, err := s.Client.UserV2.AddHumanUser(ctx, &user.AddHumanUserRequest{ Organisation: &object.Organisation{ @@ -104,6 +137,14 @@ func (s *Tester) RegisterUserPasskey(ctx context.Context, userID string) { logging.OnError(err).Fatal("create user passkey") } +func (s *Tester) SetUserPassword(ctx context.Context, userID, password string) { + _, err := s.Client.UserV2.SetPassword(ctx, &user.SetPasswordRequest{ + UserId: userID, + NewPassword: &user.Password{Password: password}, + }) + logging.OnError(err).Fatal("set user password") +} + func (s *Tester) AddGenericOAuthProvider(t *testing.T) string { ctx := authz.WithInstance(context.Background(), s.Instance) id, _, err := s.Commands.AddOrgGenericOAuthProvider(ctx, s.Organisation.ID, command.GenericOAuthProvider{ @@ -158,3 +199,51 @@ func (s *Tester) CreateSuccessfulIntent(t *testing.T, idpID, userID, idpUserID s require.NoError(t, err) return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence } + +func (s *Tester) CreatePasskeySession(t *testing.T, ctx context.Context, userID string) (id, token string, start, change time.Time) { + createResp, err := s.Client.SessionV2.CreateSession(ctx, &session.CreateSessionRequest{ + Checks: &session.Checks{ + User: &session.CheckUser{ + Search: &session.CheckUser_UserId{UserId: userID}, + }, + }, + Challenges: []session.ChallengeKind{ + session.ChallengeKind_CHALLENGE_KIND_PASSKEY, + }, + Domain: s.Config.ExternalDomain, + }) + require.NoError(t, err) + + assertion, err := s.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetPasskey().GetPublicKeyCredentialRequestOptions()) + require.NoError(t, err) + + updateResp, err := s.Client.SessionV2.SetSession(ctx, &session.SetSessionRequest{ + SessionId: createResp.GetSessionId(), + SessionToken: createResp.GetSessionToken(), + Checks: &session.Checks{ + Passkey: &session.CheckPasskey{ + CredentialAssertionData: assertion, + }, + }, + }) + require.NoError(t, err) + return createResp.GetSessionId(), updateResp.GetSessionToken(), + createResp.GetDetails().GetChangeDate().AsTime(), updateResp.GetDetails().GetChangeDate().AsTime() +} + +func (s *Tester) CreatePasswordSession(t *testing.T, ctx context.Context, userID, password string) (id, token string, start, change time.Time) { + createResp, err := s.Client.SessionV2.CreateSession(ctx, &session.CreateSessionRequest{ + Checks: &session.Checks{ + User: &session.CheckUser{ + Search: &session.CheckUser_UserId{UserId: userID}, + }, + Password: &session.CheckPassword{ + Password: password, + }, + }, + Domain: s.Config.ExternalDomain, + }) + require.NoError(t, err) + return createResp.GetSessionId(), createResp.GetSessionToken(), + createResp.GetDetails().GetChangeDate().AsTime(), createResp.GetDetails().GetChangeDate().AsTime() +} diff --git a/internal/integration/config/system-user-key.pem b/internal/integration/config/system-user-key.pem new file mode 100644 index 000000000..2c7a6e7f1 --- /dev/null +++ b/internal/integration/config/system-user-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAzi+FFSJL7f5yw4KTwzgMP34ePGycm/M+kT0M7V4Cgx5V3EaD +IvTQKTLfBaEB45zb9LtjIXzDw0rXRoS2hO6th+CYQCz3KCvh09C0IzxZiB2IS3H/ +aT+5Bx9EFY+vnAkZjccbyG5YNRvmtOlnvIeIH7qZ0tEwkPfF5GEZNPJPtmy3UGV7 +iofdVQS1xRj73+aMw5rvH4D8IdyiAC3VekIbpt0Vj0SUX3DwKtog337BzTiPk3aX +RF0sbFhQoqdJRI8NqgZjCwjq9yfI5tyxYswn+JGzHGdHvW3idODlmwEt5K2pasiR +IWK2OGfq+w0EcltQHabuqEPgZlmhCkRdNfixBwIDAQABAoIBAA9jNoBkRdxmH/R9 +Wz+3gBqA9Aq4ZFuzJJk8QCm62V8ltWyyCnliYeKhPEm0QWrWOwghr/1AzW9Wt4g4 +wVJcabD5TwODF5L0626eZcM3bsscwR44TMJzEgD5EWC2j3mKqFCPaoBj08tq4KXh +wW8tgjgz+eTk3cYD583qfTIZX1+SzSMBpetTBsssQtGhhOB/xPiuL7hi+fXmV2rh +8mc9X6+wJ5u3zepsyK0vBeEDmurD4ZUIXFrZ0WCB/wNkSW9VKyoH+RC1asQAgqTz +glJ/NPbDJSKGvSBQydoKkqoXx7MVJ8VObFddfgo4dtOoz6YCfUVBHt8qy+E5rz5y +CICjL/kCgYEA9MnHntVVKNXtEFZPo02xgCwS3eG27ZwjYgJ1ZkCHM5BuL4MS7qbr +743/POs1Ctaok0udHl1PFB4uAG0URnmkUnWzcoJYb6Plv03F0LRdsnfuhehfIxLP +nWvxSm5n21H4ytfxm0BWY09JkLDnJZtXrgTILbuqb9Wy6TmAvUaF2YUCgYEA16Ec +ywSaLVdqPaVpsTxi7XpRJAB2Isjp6RffNEecta4S0LL7s/IO3QXDH9SYpgmgCTah +3aXhpT4hIFlpg3eBjVfbOwgqub8DgirnSQyQt99edUtHIK+K8nMdGxz6X6pfTKzK +asSH7qPlt5tz1621vC0ocXSZR7zm99/FgwILwBsCgYBOsP8nJFV4By1qbxSy3qsN +FR4LjiAMSoFlZHzxHhVYkjmZtH1FkwuNuwwuPT6T+WW/1DLyK/Tb9se7A1XdQgV9 +LLE/Qn/Dg+C7mvjYmuL0GHHpQkYzNDzh0m2DC/L/Il7kdn8I9anPyxFPHk9wW3vY +SVlAum+T/BLDvuSP9DfbMQKBgCc1j7PG8XYfOB1fj7l/volqPYjrYI/wssAE7Dxo +bTGIJrm2YhiVgmhkXNfT47IFfAlQ2twgBsjyZDmqqIoUWAVonV+9m29NMYkg3g+l +bkdRIa74ckWaRgzSK8+7VDfDFjMuFFyXwhP9z460gLsORkaie4Et75Vg3yrhkNvC +qnpTAoGBAMguDSWBbCewXnHlKGFpm+LH+OIvVKGEhtCSvfZojtNrg/JBeBebSL1n +mmT1cONO+0O5bz7uVaRd3JdnH2JFevY698zFfhVsjVCrm+fz31i5cxAgC39G2Lfl +YkTaa1AFLstnf348ZjuvBN3USUYZo3X3mxnS+uluVuRSGwIKsN0a +-----END RSA PRIVATE KEY----- diff --git a/internal/integration/config/zitadel.yaml b/internal/integration/config/zitadel.yaml index 60389d6de..14222e263 100644 --- a/internal/integration/config/zitadel.yaml +++ b/internal/integration/config/zitadel.yaml @@ -1,9 +1,21 @@ Log: Level: debug +ExternalSecure: false + TLS: Enabled: false +Telemetry: + Enabled: true + Endpoints: + - http://localhost:8081 + Headers: + single-value: "single-value" + multi-value: + - "multi-value-1" + - "multi-value-2" + FirstInstance: Org: Human: @@ -31,7 +43,13 @@ Projections: Customizations: NotificationsQuotas: RequeueEvery: 1s + Telemetry: + RequeueEvery: 5s DefaultInstance: LoginPolicy: MfaInitSkipLifetime: "0" + +SystemAPIUsers: + - tester: + KeyData: "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF6aStGRlNKTDdmNXl3NEtUd3pnTQpQMzRlUEd5Y20vTStrVDBNN1Y0Q2d4NVYzRWFESXZUUUtUTGZCYUVCNDV6YjlMdGpJWHpEdzByWFJvUzJoTzZ0CmgrQ1lRQ3ozS0N2aDA5QzBJenhaaUIySVMzSC9hVCs1Qng5RUZZK3ZuQWtaamNjYnlHNVlOUnZtdE9sbnZJZUkKSDdxWjB0RXdrUGZGNUdFWk5QSlB0bXkzVUdWN2lvZmRWUVMxeFJqNzMrYU13NXJ2SDREOElkeWlBQzNWZWtJYgpwdDBWajBTVVgzRHdLdG9nMzM3QnpUaVBrM2FYUkYwc2JGaFFvcWRKUkk4TnFnWmpDd2pxOXlmSTV0eXhZc3duCitKR3pIR2RIdlczaWRPRGxtd0V0NUsycGFzaVJJV0syT0dmcSt3MEVjbHRRSGFidXFFUGdabG1oQ2tSZE5maXgKQndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==" diff --git a/internal/integration/integration.go b/internal/integration/integration.go index 6ffec11e1..8634095f3 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -15,6 +15,7 @@ import ( "github.com/spf13/viper" "github.com/zitadel/logging" + "github.com/zitadel/oidc/v2/pkg/client" "github.com/zitadel/oidc/v2/pkg/oidc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -23,6 +24,7 @@ import ( "github.com/zitadel/zitadel/cmd" "github.com/zitadel/zitadel/cmd/start" "github.com/zitadel/zitadel/internal/api/authz" + http_util "github.com/zitadel/zitadel/internal/api/http" z_oidc "github.com/zitadel/zitadel/internal/api/oidc" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" @@ -40,6 +42,8 @@ var ( cockroachYAML []byte //go:embed config/postgres.yaml postgresYAML []byte + //go:embed config/system-user-key.pem + systemUserKey []byte ) // UserType provides constants that give @@ -53,6 +57,14 @@ type UserType int const ( Unspecified UserType = iota OrgOwner + Login + IAMOwner + SystemUser // SystemUser is a user with access to the system service. +) + +const ( + FirstInstanceUsersKey = "first" + UserPassword = "VeryS3cret!" ) // User information with a Personal Access Token. @@ -61,13 +73,29 @@ type User struct { Token string } +type InstanceUserMap map[string]map[UserType]*User + +func (m InstanceUserMap) Set(instanceID string, typ UserType, user *User) { + if m[instanceID] == nil { + m[instanceID] = make(map[UserType]*User) + } + m[instanceID][typ] = user +} + +func (m InstanceUserMap) Get(instanceID string, typ UserType) *User { + if users, ok := m[instanceID]; ok { + return users[typ] + } + return nil +} + // Tester is a Zitadel server and client with all resources available for testing. type Tester struct { *start.Server Instance authz.Instance Organisation *query.Org - Users map[UserType]User + Users InstanceUserMap Client Client WebAuthN *webauthn.Client @@ -80,11 +108,12 @@ func (s *Tester) Host() string { return fmt.Sprintf("%s:%d", s.Config.ExternalDomain, s.Config.Port) } -func (s *Tester) createClientConn(ctx context.Context) { +func (s *Tester) createClientConn(ctx context.Context, opts ...grpc.DialOption) { target := s.Host() - cc, err := grpc.DialContext(ctx, target, - grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()), - ) + cc, err := grpc.DialContext(ctx, target, append(opts, + grpc.WithBlock(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + )...) if err != nil { s.Shutdown <- os.Interrupt s.wg.Wait() @@ -124,10 +153,11 @@ func (s *Tester) pollHealth(ctx context.Context) (err error) { } const ( - SystemUser = "integration" + LoginUser = "loginClient" + MachineUser = "integration" ) -func (s *Tester) createSystemUser(ctx context.Context) { +func (s *Tester) createMachineUser(ctx context.Context, instanceId string) { var err error s.Instance, err = s.Queries.InstanceByHost(ctx, s.Host()) @@ -137,25 +167,23 @@ func (s *Tester) createSystemUser(ctx context.Context) { s.Organisation, err = s.Queries.OrgByID(ctx, true, s.Instance.DefaultOrganisationID()) logging.OnError(err).Fatal("query organisation") - query, err := query.NewUserUsernameSearchQuery(SystemUser, query.TextEquals) + usernameQuery, err := query.NewUserUsernameSearchQuery(MachineUser, query.TextEquals) logging.OnError(err).Fatal("user query") - user, err := s.Queries.GetUser(ctx, true, true, query) - + user, err := s.Queries.GetUser(ctx, true, true, usernameQuery) if errors.Is(err, sql.ErrNoRows) { _, err = s.Commands.AddMachine(ctx, &command.Machine{ ObjectRoot: models.ObjectRoot{ ResourceOwner: s.Organisation.ID, }, - Username: SystemUser, - Name: SystemUser, + Username: MachineUser, + Name: MachineUser, Description: "who cares?", AccessTokenType: domain.OIDCTokenTypeJWT, }) - logging.OnError(err).Fatal("add machine user") - user, err = s.Queries.GetUser(ctx, true, true, query) - + logging.WithFields("username", SystemUser).OnError(err).Fatal("add machine user") + user, err = s.Queries.GetUser(ctx, true, true, usernameQuery) } - logging.OnError(err).Fatal("get user") + logging.WithFields("username", SystemUser).OnError(err).Fatal("get user") _, err = s.Commands.AddOrgMember(ctx, s.Organisation.ID, user.ID, "ORG_OWNER") target := new(caos_errs.AlreadyExistsError) @@ -163,21 +191,81 @@ func (s *Tester) createSystemUser(ctx context.Context) { logging.OnError(err).Fatal("add org member") } + scopes := []string{oidc.ScopeOpenID, oidc.ScopeProfile, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner} + pat := command.NewPersonalAccessToken(user.ResourceOwner, user.ID, time.Now().Add(time.Hour), scopes, domain.UserTypeMachine) + _, err = s.Commands.AddPersonalAccessToken(ctx, pat) + logging.WithFields("username", SystemUser).OnError(err).Fatal("add pat") + s.Users.Set(instanceId, OrgOwner, &User{ + User: user, + Token: pat.Token, + }) +} + +func (s *Tester) createLoginClient(ctx context.Context) { + var err error + + s.Instance, err = s.Queries.InstanceByHost(ctx, s.Host()) + logging.OnError(err).Fatal("query instance") + ctx = authz.WithInstance(ctx, s.Instance) + + s.Organisation, err = s.Queries.OrgByID(ctx, true, s.Instance.DefaultOrganisationID()) + logging.OnError(err).Fatal("query organisation") + + usernameQuery, err := query.NewUserUsernameSearchQuery(LoginUser, query.TextEquals) + logging.WithFields("username", LoginUser).OnError(err).Fatal("user query") + user, err := s.Queries.GetUser(ctx, true, true, usernameQuery) + if errors.Is(err, sql.ErrNoRows) { + _, err = s.Commands.AddMachine(ctx, &command.Machine{ + ObjectRoot: models.ObjectRoot{ + ResourceOwner: s.Organisation.ID, + }, + Username: LoginUser, + Name: LoginUser, + Description: "who cares?", + AccessTokenType: domain.OIDCTokenTypeJWT, + }) + logging.WithFields("username", LoginUser).OnError(err).Fatal("add machine user") + user, err = s.Queries.GetUser(ctx, true, true, usernameQuery) + } + logging.WithFields("username", LoginUser).OnError(err).Fatal("get user") + scopes := []string{oidc.ScopeOpenID, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner} pat := command.NewPersonalAccessToken(user.ResourceOwner, user.ID, time.Now().Add(time.Hour), scopes, domain.UserTypeMachine) _, err = s.Commands.AddPersonalAccessToken(ctx, pat) logging.OnError(err).Fatal("add pat") - s.Users = map[UserType]User{ - OrgOwner: { - User: user, - Token: pat.Token, - }, - } + s.Users.Set(FirstInstanceUsersKey, Login, &User{ + User: user, + Token: pat.Token, + }) } -func (s *Tester) WithSystemAuthorization(ctx context.Context, u UserType) context.Context { - return metadata.AppendToOutgoingContext(ctx, "Authorization", fmt.Sprintf("Bearer %s", s.Users[u].Token)) +func (s *Tester) WithAuthorization(ctx context.Context, u UserType) context.Context { + return s.WithInstanceAuthorization(ctx, u, FirstInstanceUsersKey) +} + +func (s *Tester) WithInstanceAuthorization(ctx context.Context, u UserType, instanceID string) context.Context { + if u == SystemUser { + s.ensureSystemUser() + } + return metadata.AppendToOutgoingContext(ctx, "Authorization", fmt.Sprintf("Bearer %s", s.Users.Get(instanceID, u).Token)) +} + +func (s *Tester) ensureSystemUser() { + const ISSUER = "tester" + if s.Users.Get(FirstInstanceUsersKey, SystemUser) != nil { + return + } + audience := http_util.BuildOrigin(s.Host(), s.Server.Config.ExternalSecure) + signer, err := client.NewSignerFromPrivateKeyByte(systemUserKey, "") + logging.OnError(err).Fatal("system key signer") + jwt, err := client.SignedJWTProfileAssertion(ISSUER, []string{audience}, time.Hour, signer) + logging.OnError(err).Fatal("system key jwt") + s.Users.Set(FirstInstanceUsersKey, SystemUser, &User{Token: jwt}) +} + +func (s *Tester) WithSystemAuthorizationHTTP(u UserType) map[string]string { + return map[string]string{"Authorization": fmt.Sprintf("Bearer %s", s.Users.Get(FirstInstanceUsersKey, u).Token)} } // Done send an interrupt signal to cleanly shutdown the server. @@ -224,7 +312,9 @@ func NewTester(ctx context.Context) *Tester { } logging.OnError(err).Fatal() - tester := new(Tester) + tester := Tester{ + Users: make(InstanceUserMap), + } tester.wg.Add(1) go func(wg *sync.WaitGroup) { logging.OnError(cmd.Execute()).Fatal() @@ -237,10 +327,12 @@ func NewTester(ctx context.Context) *Tester { logging.OnError(ctx.Err()).Fatal("waiting for integration tester server") } tester.createClientConn(ctx) - tester.createSystemUser(ctx) + tester.createLoginClient(ctx) + tester.WebAuthN = webauthn.NewClient(tester.Config.WebAuthNName, tester.Config.ExternalDomain, http_util.BuildOrigin(tester.Host(), tester.Config.ExternalSecure)) + tester.createMachineUser(ctx, FirstInstanceUsersKey) tester.WebAuthN = webauthn.NewClient(tester.Config.WebAuthNName, tester.Config.ExternalDomain, "https://"+tester.Host()) - return tester + return &tester } func Contexts(timeout time.Duration) (ctx, errCtx context.Context, cancel context.CancelFunc) { diff --git a/internal/integration/oidc.go b/internal/integration/oidc.go new file mode 100644 index 000000000..e34850d5e --- /dev/null +++ b/internal/integration/oidc.go @@ -0,0 +1,185 @@ +package integration + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strings" + "time" + + "github.com/zitadel/oidc/v2/pkg/client" + "github.com/zitadel/oidc/v2/pkg/client/rp" + "github.com/zitadel/oidc/v2/pkg/client/rs" + "github.com/zitadel/oidc/v2/pkg/oidc" + + http_util "github.com/zitadel/zitadel/internal/api/http" + oidc_internal "github.com/zitadel/zitadel/internal/api/oidc" + "github.com/zitadel/zitadel/pkg/grpc/app" + "github.com/zitadel/zitadel/pkg/grpc/management" +) + +func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) { + return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{ + ProjectId: projectID, + Name: fmt.Sprintf("app-%d", time.Now().UnixNano()), + RedirectUris: []string{redirectURI}, + ResponseTypes: []app.OIDCResponseType{app.OIDCResponseType_OIDC_RESPONSE_TYPE_CODE}, + GrantTypes: []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE, app.OIDCGrantType_OIDC_GRANT_TYPE_REFRESH_TOKEN}, + AppType: app.OIDCAppType_OIDC_APP_TYPE_NATIVE, + AuthMethodType: app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, + PostLogoutRedirectUris: []string{logoutRedirectURI}, + Version: app.OIDCVersion_OIDC_VERSION_1_0, + DevMode: false, + AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT, + AccessTokenRoleAssertion: false, + IdTokenRoleAssertion: false, + IdTokenUserinfoAssertion: false, + ClockSkew: nil, + AdditionalOrigins: nil, + SkipNativeAppSuccessPage: false, + }) +} + +func (s *Tester) CreateOIDCImplicitFlowClient(ctx context.Context, redirectURI string) (*management.AddOIDCAppResponse, error) { + project, err := s.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{ + Name: fmt.Sprintf("project-%d", time.Now().UnixNano()), + }) + if err != nil { + return nil, err + } + return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{ + ProjectId: project.GetId(), + Name: fmt.Sprintf("app-%d", time.Now().UnixNano()), + RedirectUris: []string{redirectURI}, + ResponseTypes: []app.OIDCResponseType{app.OIDCResponseType_OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN}, + GrantTypes: []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_IMPLICIT}, + AppType: app.OIDCAppType_OIDC_APP_TYPE_USER_AGENT, + AuthMethodType: app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, + PostLogoutRedirectUris: nil, + Version: app.OIDCVersion_OIDC_VERSION_1_0, + DevMode: true, + AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT, + AccessTokenRoleAssertion: false, + IdTokenRoleAssertion: false, + IdTokenUserinfoAssertion: false, + ClockSkew: nil, + AdditionalOrigins: nil, + SkipNativeAppSuccessPage: false, + }) +} + +func (s *Tester) CreateProject(ctx context.Context) (*management.AddProjectResponse, error) { + return s.Client.Mgmt.AddProject(ctx, &management.AddProjectRequest{ + Name: fmt.Sprintf("project-%d", time.Now().UnixNano()), + }) +} + +func (s *Tester) CreateAPIClient(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) { + return s.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{ + ProjectId: projectID, + Name: fmt.Sprintf("api-%d", time.Now().UnixNano()), + AuthMethodType: app.APIAuthMethodType_API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT, + }) +} + +func (s *Tester) CreateOIDCAuthRequest(clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) { + provider, err := s.CreateRelyingParty(clientID, redirectURI, scope...) + if err != nil { + return "", err + } + + codeVerifier := "codeVerifier" + codeChallenge := oidc.NewSHACodeChallenge(codeVerifier) + authURL := rp.AuthURL("state", provider, rp.WithCodeChallenge(codeChallenge)) + + loc, err := CheckRedirect(authURL, map[string]string{oidc_internal.LoginClientHeader: loginClient}) + if err != nil { + return "", err + } + + prefixWithHost := provider.Issuer() + s.Config.OIDC.DefaultLoginURLV2 + if !strings.HasPrefix(loc.String(), prefixWithHost) { + return "", fmt.Errorf("login location has not prefix %s, but is %s", prefixWithHost, loc.String()) + } + return strings.TrimPrefix(loc.String(), prefixWithHost), nil +} + +func (s *Tester) CreateOIDCAuthRequestImplicit(clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) { + provider, err := s.CreateRelyingParty(clientID, redirectURI, scope...) + if err != nil { + return "", err + } + + authURL := rp.AuthURL("state", provider) + + // implicit is not natively supported so let's just overwrite the response type + parsed, _ := url.Parse(authURL) + queries := parsed.Query() + queries.Set("response_type", string(oidc.ResponseTypeIDToken)) + parsed.RawQuery = queries.Encode() + authURL = parsed.String() + + loc, err := CheckRedirect(authURL, map[string]string{oidc_internal.LoginClientHeader: loginClient}) + if err != nil { + return "", err + } + + prefixWithHost := provider.Issuer() + s.Config.OIDC.DefaultLoginURLV2 + if !strings.HasPrefix(loc.String(), prefixWithHost) { + return "", fmt.Errorf("login location has not prefix %s, but is %s", prefixWithHost, loc.String()) + } + return strings.TrimPrefix(loc.String(), prefixWithHost), nil +} + +func (s *Tester) OIDCIssuer() string { + return http_util.BuildHTTP(s.Config.ExternalDomain, s.Config.Port, s.Config.ExternalSecure) +} + +func (s *Tester) CreateRelyingParty(clientID, redirectURI string, scope ...string) (rp.RelyingParty, error) { + if len(scope) == 0 { + scope = []string{oidc.ScopeOpenID} + } + loginClient := &http.Client{Transport: &loginRoundTripper{http.DefaultTransport}} + return rp.NewRelyingPartyOIDC(s.OIDCIssuer(), clientID, "", redirectURI, scope, rp.WithHTTPClient(loginClient)) +} + +type loginRoundTripper struct { + http.RoundTripper +} + +func (c *loginRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set(oidc_internal.LoginClientHeader, LoginUser) + return c.RoundTripper.RoundTrip(req) +} + +func (s *Tester) CreateResourceServer(keyFileData []byte) (rs.ResourceServer, error) { + keyFile, err := client.ConfigFromKeyFileData(keyFileData) + if err != nil { + return nil, err + } + return rs.NewResourceServerJWTProfile(s.OIDCIssuer(), keyFile.ClientID, keyFile.KeyID, []byte(keyFile.Key)) +} + +func CheckRedirect(url string, headers map[string]string) (*url.URL, error) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + for key, value := range headers { + req.Header.Set(key, value) + } + + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return resp.Location() +} diff --git a/internal/integration/rand.go b/internal/integration/rand.go new file mode 100644 index 000000000..4425c97c8 --- /dev/null +++ b/internal/integration/rand.go @@ -0,0 +1,20 @@ +package integration + +import ( + "math/rand" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz") + +func randString(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} diff --git a/internal/notification/channels/webhook/channel.go b/internal/notification/channels/webhook/channel.go index 6dbed74eb..c587f593b 100644 --- a/internal/notification/channels/webhook/channel.go +++ b/internal/notification/channels/webhook/channel.go @@ -21,10 +21,8 @@ func InitChannel(ctx context.Context, cfg Config) (channels.NotificationChannel, logging.Debug("successfully initialized webhook json channel") return channels.HandleMessageFunc(func(message channels.Message) error { - requestCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - msg, ok := message.(*messages.JSON) if !ok { return errors.ThrowInternal(nil, "WEBH-K686U", "message is not JSON") @@ -33,27 +31,24 @@ func InitChannel(ctx context.Context, cfg Config) (channels.NotificationChannel, if err != nil { return err } - req, err := http.NewRequestWithContext(requestCtx, cfg.Method, cfg.CallURL, strings.NewReader(payload)) if err != nil { return err } - + if cfg.Headers != nil { + req.Header = cfg.Headers + } req.Header.Set("Content-Type", "application/json") - resp, err := http.DefaultClient.Do(req) if err != nil { return err } - if err = resp.Body.Close(); err != nil { return err } - if resp.StatusCode < 200 || resp.StatusCode >= 300 { return errors.ThrowUnknown(fmt.Errorf("calling url %s returned %s", cfg.CallURL, resp.Status), "WEBH-LBxU0", "webhook didn't return a success status") } - logging.WithFields("calling_url", cfg.CallURL, "method", cfg.Method).Debug("webhook called") return nil }), nil diff --git a/internal/notification/channels/webhook/config.go b/internal/notification/channels/webhook/config.go index 4af0c1540..9772151d8 100644 --- a/internal/notification/channels/webhook/config.go +++ b/internal/notification/channels/webhook/config.go @@ -1,12 +1,14 @@ package webhook import ( + "net/http" "net/url" ) type Config struct { CallURL string Method string + Headers http.Header } func (w *Config) Validate() error { diff --git a/internal/notification/handlers/already_handled.go b/internal/notification/handlers/already_handled.go index abf7eb901..556a3e33c 100644 --- a/internal/notification/handlers/already_handled.go +++ b/internal/notification/handlers/already_handled.go @@ -4,16 +4,15 @@ import ( "context" "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/repository/user" ) -func (n *NotificationQueries) IsAlreadyHandled(ctx context.Context, event eventstore.Event, data map[string]interface{}, eventTypes ...eventstore.EventType) (bool, error) { +func (n *NotificationQueries) IsAlreadyHandled(ctx context.Context, event eventstore.Event, data map[string]interface{}, aggregateType eventstore.AggregateType, eventTypes ...eventstore.EventType) (bool, error) { events, err := n.es.Filter( ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). InstanceID(event.Aggregate().InstanceID). AddQuery(). - AggregateTypes(user.AggregateType). + AggregateTypes(aggregateType). AggregateIDs(event.Aggregate().ID). SequenceGreater(event.Sequence()). EventTypes(eventTypes...). diff --git a/internal/notification/handlers/handlers_integration_test.go b/internal/notification/handlers/handlers_integration_test.go new file mode 100644 index 000000000..37f6a344c --- /dev/null +++ b/internal/notification/handlers/handlers_integration_test.go @@ -0,0 +1,30 @@ +//go:build integration + +package handlers_test + +import ( + "context" + "os" + "testing" + "time" + + "github.com/zitadel/zitadel/internal/integration" +) + +var ( + CTX context.Context + SystemCTX context.Context + Tester *integration.Tester +) + +func TestMain(m *testing.M) { + os.Exit(func() int { + ctx, _, cancel := integration.Contexts(5 * time.Minute) + CTX = ctx + defer cancel() + Tester = integration.NewTester(ctx) + SystemCTX = Tester.WithAuthorization(ctx, integration.SystemUser) + defer Tester.Done() + return m.Run() + }()) +} diff --git a/internal/notification/handlers/queries.go b/internal/notification/handlers/queries.go index 63e0ab4d4..96880445b 100644 --- a/internal/notification/handlers/queries.go +++ b/internal/notification/handlers/queries.go @@ -12,6 +12,7 @@ import ( type NotificationQueries struct { *query.Queries es *eventstore.Eventstore + externalDomain string externalPort uint16 externalSecure bool fileSystemPath string @@ -24,6 +25,7 @@ type NotificationQueries struct { func NewNotificationQueries( baseQueries *query.Queries, es *eventstore.Eventstore, + externalDomain string, externalPort uint16, externalSecure bool, fileSystemPath string, @@ -35,6 +37,7 @@ func NewNotificationQueries( return &NotificationQueries{ Queries: baseQueries, es: es, + externalDomain: externalDomain, externalPort: externalPort, externalSecure: externalSecure, fileSystemPath: fileSystemPath, diff --git a/internal/notification/handlers/quotanotifier.go b/internal/notification/handlers/quota_notifier.go similarity index 96% rename from internal/notification/handlers/quotanotifier.go rename to internal/notification/handlers/quota_notifier.go index e53998490..21daa92ff 100644 --- a/internal/notification/handlers/quotanotifier.go +++ b/internal/notification/handlers/quota_notifier.go @@ -68,7 +68,7 @@ func (u *quotaNotifier) reduceNotificationDue(event eventstore.Event) (*handler. return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-DLxdE", "reduce.wrong.event.type %s", quota.NotificationDueEventType) } ctx := HandlerContext(event.Aggregate()) - alreadyHandled, err := u.queries.IsAlreadyHandled(ctx, event, map[string]interface{}{"dueEventID": e.ID}, quota.NotifiedEventType) + alreadyHandled, err := u.queries.IsAlreadyHandled(ctx, event, map[string]interface{}{"dueEventID": e.ID}, quota.AggregateType, quota.NotifiedEventType) if err != nil { return nil, err } diff --git a/internal/notification/handlers/telemetry_pusher.go b/internal/notification/handlers/telemetry_pusher.go new file mode 100644 index 000000000..86f8420c7 --- /dev/null +++ b/internal/notification/handlers/telemetry_pusher.go @@ -0,0 +1,156 @@ +package handlers + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/call" + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/handler" + "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" + "github.com/zitadel/zitadel/internal/notification/channels/webhook" + _ "github.com/zitadel/zitadel/internal/notification/statik" + "github.com/zitadel/zitadel/internal/notification/types" + "github.com/zitadel/zitadel/internal/query" + "github.com/zitadel/zitadel/internal/query/projection" + "github.com/zitadel/zitadel/internal/repository/milestone" + "github.com/zitadel/zitadel/internal/repository/pseudo" +) + +const ( + TelemetryProjectionTable = "projections.telemetry" +) + +type TelemetryPusherConfig struct { + Enabled bool + Endpoints []string + Headers http.Header + Limit uint64 +} + +type telemetryPusher struct { + crdb.StatementHandler + cfg TelemetryPusherConfig + commands *command.Commands + queries *NotificationQueries + metricSuccessfulDeliveriesJSON string + metricFailedDeliveriesJSON string +} + +func NewTelemetryPusher( + ctx context.Context, + telemetryCfg TelemetryPusherConfig, + handlerCfg crdb.StatementHandlerConfig, + commands *command.Commands, + queries *NotificationQueries, + metricSuccessfulDeliveriesJSON, + metricFailedDeliveriesJSON string, +) *telemetryPusher { + p := new(telemetryPusher) + handlerCfg.ProjectionName = TelemetryProjectionTable + handlerCfg.Reducers = p.reducers() + p.cfg = telemetryCfg + p.StatementHandler = crdb.NewStatementHandler(ctx, handlerCfg) + p.commands = commands + p.queries = queries + p.metricSuccessfulDeliveriesJSON = metricSuccessfulDeliveriesJSON + p.metricFailedDeliveriesJSON = metricFailedDeliveriesJSON + projection.TelemetryPusherProjection = p + return p +} + +func (t *telemetryPusher) reducers() []handler.AggregateReducer { + return []handler.AggregateReducer{{ + Aggregate: pseudo.AggregateType, + EventRedusers: []handler.EventReducer{{ + Event: pseudo.ScheduledEventType, + Reduce: t.pushMilestones, + }}, + }} +} + +func (t *telemetryPusher) pushMilestones(event eventstore.Event) (*handler.Statement, error) { + ctx := call.WithTimestamp(context.Background()) + scheduledEvent, ok := event.(*pseudo.ScheduledEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-lDTs5", "reduce.wrong.event.type %s", event.Type()) + } + + isReached, err := query.NewNotNullQuery(query.MilestoneReachedDateColID) + if err != nil { + return nil, err + } + isNotPushed, err := query.NewIsNullQuery(query.MilestonePushedDateColID) + if err != nil { + return nil, err + } + hasPrimaryDomain, err := query.NewNotNullQuery(query.MilestonePrimaryDomainColID) + if err != nil { + return nil, err + } + unpushedMilestones, err := t.queries.Queries.SearchMilestones(ctx, scheduledEvent.InstanceIDs, &query.MilestonesSearchQueries{ + SearchRequest: query.SearchRequest{ + Limit: t.cfg.Limit, + SortingColumn: query.MilestoneReachedDateColID, + Asc: true, + }, + Queries: []query.SearchQuery{isReached, isNotPushed, hasPrimaryDomain}, + }) + if err != nil { + return nil, err + } + var errs int + for _, ms := range unpushedMilestones.Milestones { + if err = t.pushMilestone(ctx, scheduledEvent, ms); err != nil { + errs++ + logging.Warnf("pushing milestone %+v failed: %s", *ms, err.Error()) + } + } + if errs > 0 { + return nil, fmt.Errorf("pushing %d of %d milestones failed", errs, unpushedMilestones.Count) + } + + return crdb.NewNoOpStatement(scheduledEvent), nil +} + +func (t *telemetryPusher) pushMilestone(ctx context.Context, event *pseudo.ScheduledEvent, ms *query.Milestone) error { + ctx = authz.WithInstanceID(ctx, ms.InstanceID) + for _, endpoint := range t.cfg.Endpoints { + if err := types.SendJSON( + ctx, + webhook.Config{ + CallURL: endpoint, + Method: http.MethodPost, + Headers: t.cfg.Headers, + }, + t.queries.GetFileSystemProvider, + t.queries.GetLogProvider, + &struct { + InstanceID string `json:"instanceId"` + ExternalDomain string `json:"externalDomain"` + PrimaryDomain string `json:"primaryDomain"` + Type milestone.Type `json:"type"` + ReachedDate time.Time `json:"reached"` + }{ + InstanceID: ms.InstanceID, + ExternalDomain: t.queries.externalDomain, + PrimaryDomain: ms.PrimaryDomain, + Type: ms.Type, + ReachedDate: ms.ReachedDate, + }, + event, + t.metricSuccessfulDeliveriesJSON, + t.metricFailedDeliveriesJSON, + ).WithoutTemplate(); err != nil { + return err + } + } + return t.commands.MilestonePushed(ctx, ms.Type, t.cfg.Endpoints, ms.PrimaryDomain) +} diff --git a/internal/notification/handlers/telemetry_pusher_integration_test.go b/internal/notification/handlers/telemetry_pusher_integration_test.go new file mode 100644 index 000000000..e3709db17 --- /dev/null +++ b/internal/notification/handlers/telemetry_pusher_integration_test.go @@ -0,0 +1,89 @@ +//go:build integration + +package handlers_test + +import ( + "bytes" + "encoding/json" + "io" + "net" + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" + + "github.com/zitadel/zitadel/pkg/grpc/management" + "github.com/zitadel/zitadel/pkg/grpc/system" +) + +func TestServer_TelemetryPushMilestones(t *testing.T) { + bodies := make(chan []byte, 0) + mockServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + if err != nil { + t.Error(err) + } + if r.Header.Get("single-value") != "single-value" { + t.Error("single-value header not set") + } + if reflect.DeepEqual(r.Header.Get("multi-value"), "multi-value-1,multi-value-2") { + t.Error("single-value header not set") + } + bodies <- body + w.WriteHeader(http.StatusOK) + })) + listener, err := net.Listen("tcp", "localhost:8081") + if err != nil { + t.Fatal(err) + } + mockServer.Listener = listener + mockServer.Start() + t.Cleanup(mockServer.Close) + primaryDomain, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(CTX, SystemCTX) + t.Log("testing against instance with primary domain", primaryDomain) + awaitMilestone(t, bodies, primaryDomain, "InstanceCreated") + project, err := Tester.Client.Mgmt.AddProject(iamOwnerCtx, &management.AddProjectRequest{Name: "integration"}) + if err != nil { + t.Fatal(err) + } + awaitMilestone(t, bodies, primaryDomain, "ProjectCreated") + if _, err = Tester.Client.Mgmt.AddOIDCApp(iamOwnerCtx, &management.AddOIDCAppRequest{ + ProjectId: project.GetId(), + Name: "integration", + }); err != nil { + t.Fatal(err) + } + awaitMilestone(t, bodies, primaryDomain, "ApplicationCreated") + // TODO: trigger and await milestone AuthenticationSucceededOnInstance + // TODO: trigger and await milestone AuthenticationSucceededOnApplication + if _, err = Tester.Client.System.RemoveInstance(SystemCTX, &system.RemoveInstanceRequest{InstanceId: instanceID}); err != nil { + t.Fatal(err) + } + awaitMilestone(t, bodies, primaryDomain, "InstanceDeleted") +} + +func awaitMilestone(t *testing.T, bodies chan []byte, primaryDomain, expectMilestoneType string) { + for { + select { + case body := <-bodies: + plain := new(bytes.Buffer) + if err := json.Indent(plain, body, "", " "); err != nil { + t.Fatal(err) + } + t.Log("received milestone", plain.String()) + milestone := struct { + Type string `json:"type"` + PrimaryDomain string `json:"primaryDomain"` + }{} + if err := json.Unmarshal(body, &milestone); err != nil { + t.Error(err) + } + if milestone.Type == expectMilestoneType && milestone.PrimaryDomain == primaryDomain { + return + } + case <-time.After(60 * time.Second): + t.Fatalf("timed out waiting for milestone %s in domain %s", expectMilestoneType, primaryDomain) + } + } +} diff --git a/internal/notification/handlers/usernotifier.go b/internal/notification/handlers/user_notifier.go similarity index 99% rename from internal/notification/handlers/usernotifier.go rename to internal/notification/handlers/user_notifier.go index cd2a48f09..d726fb62a 100644 --- a/internal/notification/handlers/usernotifier.go +++ b/internal/notification/handlers/user_notifier.go @@ -337,7 +337,7 @@ func (u *userNotifier) reduceDomainClaimed(event eventstore.Event) (*handler.Sta return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Drh5w", "reduce.wrong.event.type %s", user.UserDomainClaimedType) } ctx := HandlerContext(event.Aggregate()) - alreadyHandled, err := u.queries.IsAlreadyHandled(ctx, event, nil, + alreadyHandled, err := u.queries.IsAlreadyHandled(ctx, event, nil, user.AggregateType, user.UserDomainClaimedType, user.UserDomainClaimedSentType) if err != nil { return nil, err @@ -465,7 +465,7 @@ func (u *userNotifier) reducePasswordChanged(event eventstore.Event) (*handler.S return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Yko2z8", "reduce.wrong.event.type %s", user.HumanPasswordChangedType) } ctx := HandlerContext(event.Aggregate()) - alreadyHandled, err := u.queries.IsAlreadyHandled(ctx, event, nil, user.HumanPasswordChangeSentType) + alreadyHandled, err := u.queries.IsAlreadyHandled(ctx, event, nil, user.AggregateType, user.HumanPasswordChangeSentType) if err != nil { return nil, err } @@ -594,5 +594,5 @@ func (u *userNotifier) checkIfCodeAlreadyHandledOrExpired(ctx context.Context, e if event.CreationDate().Add(expiry).Before(time.Now().UTC()) { return true, nil } - return u.queries.IsAlreadyHandled(ctx, event, data, eventTypes...) + return u.queries.IsAlreadyHandled(ctx, event, data, user.AggregateType, eventTypes...) } diff --git a/internal/notification/projections.go b/internal/notification/projections.go index f4abf3b7b..0a6f6f659 100644 --- a/internal/notification/projections.go +++ b/internal/notification/projections.go @@ -29,6 +29,9 @@ func Start( ctx context.Context, userHandlerCustomConfig projection.CustomConfig, quotaHandlerCustomConfig projection.CustomConfig, + telemetryHandlerCustomConfig projection.CustomConfig, + telemetryCfg handlers.TelemetryPusherConfig, + externalDomain string, externalPort uint16, externalSecure bool, commands *command.Commands, @@ -54,7 +57,7 @@ func Start( logging.WithFields("metric", metricSuccessfulDeliveriesJSON).OnError(err).Panic("unable to register counter") err = metrics.RegisterCounter(metricFailedDeliveriesJSON, "Failed JSON message deliveries") logging.WithFields("metric", metricFailedDeliveriesJSON).OnError(err).Panic("unable to register counter") - q := handlers.NewNotificationQueries(queries, es, externalPort, externalSecure, fileSystemPath, userEncryption, smtpEncryption, smsEncryption, statikFS) + q := handlers.NewNotificationQueries(queries, es, externalDomain, externalPort, externalSecure, fileSystemPath, userEncryption, smtpEncryption, smsEncryption, statikFS) handlers.NewUserNotifier( ctx, projection.ApplyCustomConfig(userHandlerCustomConfig), @@ -74,4 +77,15 @@ func Start( metricSuccessfulDeliveriesJSON, metricFailedDeliveriesJSON, ).Start() + if telemetryCfg.Enabled { + handlers.NewTelemetryPusher( + ctx, + telemetryCfg, + projection.ApplyCustomConfig(telemetryHandlerCustomConfig), + commands, + q, + metricSuccessfulDeliveriesJSON, + metricFailedDeliveriesJSON, + ).Start() + } } diff --git a/internal/notification/static/i18n/mk.yaml b/internal/notification/static/i18n/mk.yaml new file mode 100644 index 000000000..b2c5573ae --- /dev/null +++ b/internal/notification/static/i18n/mk.yaml @@ -0,0 +1,49 @@ +InitCode: + Title: ZITADEL - Иницијализација на Корисник + PreHeader: Иницијализација на Корисник + Subject: Иницијализација на Корисник + Greeting: Здраво {{.DisplayName}}, + Text: Овој корисник е креиран во ZITADEL. Користете го корисничкото име {{.PreferredLoginName}} за најава. Ве молиме кликнете на копчето подолу за да го завршите процесот на иницијализација. (Код {{.Code}}) Ако не сте барале/и оваа е-пошта, ве молиме игнорирајте ја. + ButtonText: Заврши иницијализација +PasswordReset: + Title: ZITADEL - Ресетирање на лозинка + PreHeader: Ресетирање на лозинка + Subject: Ресетирање на лозинка + Greeting: Здраво {{.DisplayName}}, + Text: Добивме барање за ресетирање на лозинката. Ве молиме користете го копчето подолу за да ја ресетирате вашата лозинка. (Код {{.Code}}) Ако не сте ја побарале ресетирање на лозинка, ве молиме игнорирајте ја оваа е-пошта. + ButtonText: Ресетирај лозинка +VerifyEmail: + Title: ZITADEL - Верификација на е-пошта + PreHeader: Верификација на е-пошта + Subject: Верификација на е-пошта + Greeting: Здраво {{.DisplayName}}, + Text: Додадена е нова е-пошта. Ве молиме користете го копчето подолу за да ја верифицирате вашата е-пошта. (Код {{.Code}}) Ако не сте додале нова е-пошта, ве молиме игнорирајте ја оваа е-пошта. + ButtonText: Верифицирај е-пошта +VerifyPhone: + Title: ZITADEL - Верификација на телефонски број + PreHeader: Верификација на телефонски број + Subject: Верификација на телефонски број + Greeting: Здраво {{.DisplayName}}, + Text: Додаден е нов телефонски број. Ве молиме користете го следниот код за да го верифицирате. {{.Code}} + ButtonText: Верифицирај телефонски број +DomainClaimed: + Title: ZITADEL - Доменот е преземен + PreHeader: Промена на е-пошта / корисничко име + Subject: Доменот е преземен + Greeting: Здраво {{.DisplayName}}, + Text: Доменот {{.Domain}} е преземен од страна на организација. Вашиот моментален корисник {{.Username}} не е дел од оваа организација. Затоа, при најава, треба да го промените вашиот е-поштенска адреса. Направивме привремено корисничко име ({{.TempUsername}}) за оваа најава. + ButtonText: Најави се +PasswordlessRegistration: + Title: ZITADEL - Додади Најава без Лозинка + PreHeader: Додади Најава без Лозинка + Subject: Додади Најава без Лозинка + Greeting: Здраво {{.DisplayName}}, + Text: Добивме барање да додадеме токен за најава без лозинка. Ве молиме користете го копчето подолу за да додадете вашиот токен или уред за најава без лозинка. + ButtonText: Додади Најава без Лозинка +PasswordChange: + Title: ZITADEL - Лозинката на корисникот е променета + PreHeader: Промена на лозинка + Subject: Лозинката на корисникот е променета + Greeting: Здраво {{.DisplayName}}, + Text: Лозинката на вашиот корисник е променета. Ако оваа промена не е извршена од вас, ве молиме веднаш ресетирајте ја вашата лозинка. + ButtonText: Најава diff --git a/internal/notification/static/i18n/pt.yaml b/internal/notification/static/i18n/pt.yaml new file mode 100644 index 000000000..7aa46efd8 --- /dev/null +++ b/internal/notification/static/i18n/pt.yaml @@ -0,0 +1,49 @@ +InitCode: + Title: ZITADEL - Inicializar Usuário + PreHeader: Inicializar Usuário + Subject: Inicializar Usuário + Greeting: Olá {{.DisplayName}}, + Text: Este usuário foi criado no ZITADEL. Use o nome de usuário {{.PreferredLoginName}} para fazer login. Por favor, clique no botão abaixo para finalizar o processo de inicialização. (Código {{.Code}}) Se você não solicitou este e-mail, por favor, ignore-o. + ButtonText: Finalizar inicialização +PasswordReset: + Title: ZITADEL - Redefinir senha + PreHeader: Redefinir senha + Subject: Redefinir senha + Greeting: Olá {{.DisplayName}}, + Text: Recebemos uma solicitação de redefinição de senha. Por favor, use o botão abaixo para redefinir sua senha. (Código {{.Code}}) Se você não solicitou este e-mail, por favor, ignore-o. + ButtonText: Redefinir senha +VerifyEmail: + Title: ZITADEL - Verificar e-mail + PreHeader: Verificar e-mail + Subject: Verificar e-mail + Greeting: Olá {{.DisplayName}}, + Text: Um novo e-mail foi adicionado. Por favor, use o botão abaixo para verificar seu e-mail. (Código {{.Code}}) Se você não adicionou um novo e-mail, por favor, ignore este e-mail. + ButtonText: Verificar e-mail +VerifyPhone: + Title: ZITADEL - Verificar telefone + PreHeader: Verificar telefone + Subject: Verificar telefone + Greeting: Olá {{.DisplayName}}, + Text: Um novo número de telefone foi adicionado. Por favor, use o código a seguir para verificá-lo {{.Code}} + ButtonText: Verificar telefone +DomainClaimed: + Title: ZITADEL - Domínio foi reivindicado + PreHeader: Alterar e-mail / nome de usuário + Subject: Domínio foi reivindicado + Greeting: Olá {{.DisplayName}}, + Text: O domínio {{.Domain}} foi reivindicado por uma organização. Seu usuário atual, {{.Username}}, não faz parte dessa organização. Portanto, você terá que alterar seu e-mail quando fizer o login. Criamos um nome de usuário temporário ({{.TempUsername}}) para este login. + ButtonText: Fazer login +PasswordlessRegistration: + Title: ZITADEL - Adicionar Login sem Senha + PreHeader: Adicionar Login sem Senha + Subject: Adicionar Login sem Senha + Greeting: Olá {{.DisplayName}}, + Text: Recebemos uma solicitação para adicionar um token ou dispositivo para login sem senha. Por favor, use o botão abaixo para adicionar seu token ou dispositivo para login sem senha. + ButtonText: Adicionar Login sem Senha +PasswordChange: + Title: ZITADEL - Senha do usuário foi alterada + PreHeader: Alterar senha + Subject: Senha do usuário foi alterada + Greeting: Olá {{.DisplayName}}, + Text: A senha do seu usuário foi alterada. Se esta alteração não foi feita por você, recomendamos que você redefina sua senha imediatamente. + ButtonText: Fazer login diff --git a/internal/org/model/org.go b/internal/org/model/org.go index a944a6897..4267506b5 100644 --- a/internal/org/model/org.go +++ b/internal/org/model/org.go @@ -1,8 +1,7 @@ package model import ( - "strings" - + "github.com/zitadel/zitadel/internal/domain" es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" iam_model "github.com/zitadel/zitadel/internal/iam/model" ) @@ -46,10 +45,6 @@ func (o *Org) GetPrimaryDomain() *OrgDomain { return nil } -func (o *Org) nameForDomain(iamDomain string) string { - return strings.ToLower(strings.ReplaceAll(o.Name, " ", "-") + "." + iamDomain) -} - func (o *Org) AddIAMDomain(iamDomain string) { - o.Domains = append(o.Domains, &OrgDomain{Domain: o.nameForDomain(iamDomain), Verified: true, Primary: true}) + o.Domains = append(o.Domains, &OrgDomain{Domain: domain.NewIAMDomainName(o.Name, iamDomain), Verified: true, Primary: true}) } diff --git a/internal/protoc/protoc-base/protoc_helper.go b/internal/protoc/protoc-base/protoc_helper.go deleted file mode 100644 index ecf9150c8..000000000 --- a/internal/protoc/protoc-base/protoc_helper.go +++ /dev/null @@ -1,113 +0,0 @@ -package protocbase - -import ( - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "text/template" - - "github.com/golang/glog" - "github.com/golang/protobuf/proto" - plugin "github.com/golang/protobuf/protoc-gen-go/plugin" - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" -) - -type GeneratorFunc func(target string, registry *descriptor.Registry, file *descriptor.File) (string, string, error) - -type ProtocGenerator interface { - Generate(target string, registry *descriptor.Registry, file *descriptor.File) (string, string, error) -} - -func (f GeneratorFunc) Generate(target string, registry *descriptor.Registry, file *descriptor.File) (string, string, error) { - return f(target, registry, file) //TODO: in my opinion we should use file.GoPkg here analog https://github.com/grpc-ecosystem/grpc-gateway/blob/0cc2680a4990244dcc7602bad34fef935310c0e8/protoc-gen-grpc-gateway/internal/gengateway/generator.go#L111 -} - -func parseReq(r io.Reader) (*plugin.CodeGeneratorRequest, error) { - glog.V(1).Info("Parsing code generator request") - - input, err := ioutil.ReadAll(r) - - if err != nil { - glog.Errorf("Failed to read code generator request: %v", err) - return nil, err - } - - req := &plugin.CodeGeneratorRequest{} - - if err = proto.Unmarshal(input, req); err != nil { - glog.Errorf("Failed to unmarshal code generator request: %v", err) - return nil, err - } - - glog.V(1).Info("Parsed code generator request") - - return req, nil -} - -func RunWithBaseTemplate(targetFileNameFmt string, tmpl *template.Template) { - Run(GeneratorFunc(func(target string, registry *descriptor.Registry, file *descriptor.File) (string, string, error) { - fileName := fmt.Sprintf(targetFileNameFmt, strings.Split(target, ".")[0]) - fContent, err := GenerateFromBaseTemplate(tmpl, registry, file) - return fileName, fContent, err - })) -} - -func Run(generator ProtocGenerator) { - flag.Parse() - defer glog.Flush() - - req, err := parseReq(os.Stdin) - if err != nil { - glog.Fatal(err) - } - - registry := descriptor.NewRegistry() - registry.SetAllowDeleteBody(true) - if err = registry.Load(req); err != nil { - glog.Fatal(err) - } - - var result []*plugin.CodeGeneratorResponse_File - - for _, t := range req.FileToGenerate { - file, err := registry.LookupFile(t) - if err != nil { - EmitError(err) - return - } - - fName, fContent, err := generator.Generate(t, registry, file) - if err != nil { - EmitError(err) - return - } - - result = append(result, &plugin.CodeGeneratorResponse_File{ - Name: &fName, - Content: &fContent, - }) - } - - EmitFiles(result) -} - -func EmitFiles(out []*plugin.CodeGeneratorResponse_File) { - EmitResp(&plugin.CodeGeneratorResponse{File: out}) -} - -func EmitError(err error) { - EmitResp(&plugin.CodeGeneratorResponse{Error: proto.String(err.Error())}) -} - -func EmitResp(resp *plugin.CodeGeneratorResponse) { - buf, err := proto.Marshal(resp) - if err != nil { - glog.Fatal(err) - } - if _, err := os.Stdout.Write(buf); err != nil { - glog.Fatal(err) - } -} diff --git a/internal/protoc/protoc-base/templates.go b/internal/protoc/protoc-base/templates.go deleted file mode 100644 index 57e1c0364..000000000 --- a/internal/protoc/protoc-base/templates.go +++ /dev/null @@ -1,106 +0,0 @@ -package protocbase - -import ( - "bytes" - "fmt" - "text/template" - "time" - - "github.com/Masterminds/sprig" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" - "golang.org/x/tools/imports" -) - -var extensions = map[string]*proto.ExtensionDesc{} - -type BaseTemplateData struct { - Now time.Time - File *descriptor.File - - registry *descriptor.Registry -} - -var templateFuncs = map[string]interface{}{ - "option": getOption, -} - -func RegisterTmplFunc(name string, f interface{}) { - if _, found := templateFuncs[name]; found { - panic(fmt.Sprintf("func with name %v is already registered", name)) - } - - templateFuncs[name] = f -} - -func RegisterExtension(ext *proto.ExtensionDesc) { - extensions[ext.Name] = ext -} - -func GetBaseTemplateData(registry *descriptor.Registry, file *descriptor.File) *BaseTemplateData { - return &BaseTemplateData{ - Now: time.Now().UTC(), - File: file, - registry: registry, - } -} - -func getOption(opts proto.Message, extName string) interface{} { - extDesc := extensions[extName] - - if !proto.HasExtension(opts, extDesc) { - return nil - } - - ext, err := proto.GetExtension(opts, extDesc) - if err != nil { - panic(err) - } - - return ext -} - -func (data *BaseTemplateData) ResolveMsgType(msgType string) string { - msg, err := data.registry.LookupMsg(data.File.GetPackage(), msgType) - if err != nil { - panic(err) - } - - return msg.GoType(data.File.GoPkg.Path) -} - -func (data *BaseTemplateData) ResolveFile(fileName string) *descriptor.File { - file, err := data.registry.LookupFile(fileName) - if err != nil { - panic(err) - } - - return file -} - -func LoadTemplate(templateData []byte, err error) *template.Template { - if err != nil { - panic(err) - } - - return template.Must(template.New(""). - Funcs(sprig.TxtFuncMap()). - Funcs(templateFuncs). - Parse(string(templateData))) -} - -func GenerateFromTemplate(tmpl *template.Template, data interface{}) (string, error) { - var tpl bytes.Buffer - err := tmpl.Execute(&tpl, data) - if err != nil { - return "", err - } - - tmplResult := tpl.Bytes() - tmplResult, err = imports.Process(".", tmplResult, nil) - return string(tmplResult), err -} - -func GenerateFromBaseTemplate(tmpl *template.Template, registry *descriptor.Registry, file *descriptor.File) (string, error) { - return GenerateFromTemplate(tmpl, GetBaseTemplateData(registry, file)) -} diff --git a/internal/protoc/protoc-gen-auth/auth_method_mapping.go.tmpl b/internal/protoc/protoc-gen-authoption/auth_method_mapping.go.tmpl similarity index 100% rename from internal/protoc/protoc-gen-auth/auth_method_mapping.go.tmpl rename to internal/protoc/protoc-gen-authoption/auth_method_mapping.go.tmpl diff --git a/internal/protoc/protoc-gen-authoption/authoption/generate.go b/internal/protoc/protoc-gen-authoption/authoption/generate.go deleted file mode 100644 index 24ab586e3..000000000 --- a/internal/protoc/protoc-gen-authoption/authoption/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package authoption - -//go:generate protoc -I. -I$GOPATH/src --go-grpc_out=plugins=grpc:$GOPATH/src options.proto diff --git a/internal/protoc/protoc-gen-authoption/authoption/options.pb.go b/internal/protoc/protoc-gen-authoption/authoption/options.pb.go new file mode 100644 index 000000000..18d84aa42 --- /dev/null +++ b/internal/protoc/protoc-gen-authoption/authoption/options.pb.go @@ -0,0 +1,187 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc (unknown) +// source: zitadel/options.proto + +package authoption + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AuthOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Permission string `protobuf:"bytes,1,opt,name=permission,proto3" json:"permission,omitempty"` + CheckFieldName string `protobuf:"bytes,2,opt,name=check_field_name,json=checkFieldName,proto3" json:"check_field_name,omitempty"` +} + +func (x *AuthOption) Reset() { + *x = AuthOption{} + if protoimpl.UnsafeEnabled { + mi := &file_zitadel_options_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuthOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthOption) ProtoMessage() {} + +func (x *AuthOption) ProtoReflect() protoreflect.Message { + mi := &file_zitadel_options_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthOption.ProtoReflect.Descriptor instead. +func (*AuthOption) Descriptor() ([]byte, []int) { + return file_zitadel_options_proto_rawDescGZIP(), []int{0} +} + +func (x *AuthOption) GetPermission() string { + if x != nil { + return x.Permission + } + return "" +} + +func (x *AuthOption) GetCheckFieldName() string { + if x != nil { + return x.CheckFieldName + } + return "" +} + +var file_zitadel_options_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.MethodOptions)(nil), + ExtensionType: (*AuthOption)(nil), + Field: 50000, + Name: "zitadel.v1.auth_option", + Tag: "bytes,50000,opt,name=auth_option", + Filename: "zitadel/options.proto", + }, +} + +// Extension fields to descriptorpb.MethodOptions. +var ( + // optional zitadel.v1.AuthOption auth_option = 50000; + E_AuthOption = &file_zitadel_options_proto_extTypes[0] +) + +var File_zitadel_options_proto protoreflect.FileDescriptor + +var file_zitadel_options_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, + 0x2e, 0x76, 0x31, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x3a, 0x59, 0x0a, + 0x0b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd0, 0x86, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x61, 0x75, + 0x74, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, + 0x6e, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_zitadel_options_proto_rawDescOnce sync.Once + file_zitadel_options_proto_rawDescData = file_zitadel_options_proto_rawDesc +) + +func file_zitadel_options_proto_rawDescGZIP() []byte { + file_zitadel_options_proto_rawDescOnce.Do(func() { + file_zitadel_options_proto_rawDescData = protoimpl.X.CompressGZIP(file_zitadel_options_proto_rawDescData) + }) + return file_zitadel_options_proto_rawDescData +} + +var file_zitadel_options_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_zitadel_options_proto_goTypes = []interface{}{ + (*AuthOption)(nil), // 0: zitadel.v1.AuthOption + (*descriptorpb.MethodOptions)(nil), // 1: google.protobuf.MethodOptions +} +var file_zitadel_options_proto_depIdxs = []int32{ + 1, // 0: zitadel.v1.auth_option:extendee -> google.protobuf.MethodOptions + 0, // 1: zitadel.v1.auth_option:type_name -> zitadel.v1.AuthOption + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 1, // [1:2] is the sub-list for extension type_name + 0, // [0:1] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_zitadel_options_proto_init() } +func file_zitadel_options_proto_init() { + if File_zitadel_options_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_zitadel_options_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuthOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_zitadel_options_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 1, + NumServices: 0, + }, + GoTypes: file_zitadel_options_proto_goTypes, + DependencyIndexes: file_zitadel_options_proto_depIdxs, + MessageInfos: file_zitadel_options_proto_msgTypes, + ExtensionInfos: file_zitadel_options_proto_extTypes, + }.Build() + File_zitadel_options_proto = out.File + file_zitadel_options_proto_rawDesc = nil + file_zitadel_options_proto_goTypes = nil + file_zitadel_options_proto_depIdxs = nil +} diff --git a/internal/protoc/protoc-gen-authoption/authoption/options.proto b/internal/protoc/protoc-gen-authoption/authoption/options.proto deleted file mode 100644 index c62a6378e..000000000 --- a/internal/protoc/protoc-gen-authoption/authoption/options.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; - -package caos.zitadel.utils.v1; - -import "google/protobuf/descriptor.proto"; - -option go_package = "github.com/zitadel/zitadel/internal/protoc/protoc-gen-authoption/authoption"; - - -extend google.protobuf.MethodOptions { - AuthOption auth_option = 50000; -} - -message AuthOption { - string permission = 1; - string check_field_name = 2; - string feature = 3; -} \ No newline at end of file diff --git a/internal/protoc/protoc-gen-auth/main.go b/internal/protoc/protoc-gen-authoption/main.go similarity index 100% rename from internal/protoc/protoc-gen-auth/main.go rename to internal/protoc/protoc-gen-authoption/main.go diff --git a/internal/query/access_token.go b/internal/query/access_token.go new file mode 100644 index 000000000..25121af05 --- /dev/null +++ b/internal/query/access_token.go @@ -0,0 +1,152 @@ +package query + +import ( + "context" + "strings" + "time" + + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/oidcsession" + "github.com/zitadel/zitadel/internal/repository/session" + "github.com/zitadel/zitadel/internal/telemetry/tracing" +) + +type OIDCSessionAccessTokenReadModel struct { + eventstore.WriteModel + + UserID string + SessionID string + ClientID string + Audience []string + Scope []string + AuthMethods []domain.UserAuthMethodType + AuthTime time.Time + State domain.OIDCSessionState + AccessTokenID string + AccessTokenCreation time.Time + AccessTokenExpiration time.Time +} + +func newOIDCSessionAccessTokenReadModel(id string) *OIDCSessionAccessTokenReadModel { + return &OIDCSessionAccessTokenReadModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: id, + }, + } +} + +func (wm *OIDCSessionAccessTokenReadModel) Reduce() error { + for _, event := range wm.Events { + switch e := event.(type) { + case *oidcsession.AddedEvent: + wm.reduceAdded(e) + case *oidcsession.AccessTokenAddedEvent: + wm.reduceAccessTokenAdded(e) + case *oidcsession.AccessTokenRevokedEvent, + *oidcsession.RefreshTokenRevokedEvent: + wm.reduceTokenRevoked(event) + } + } + return wm.WriteModel.Reduce() +} + +func (wm *OIDCSessionAccessTokenReadModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AllowTimeTravel(). + AddQuery(). + AggregateTypes(oidcsession.AggregateType). + AggregateIDs(wm.AggregateID). + EventTypes( + oidcsession.AddedType, + oidcsession.AccessTokenAddedType, + oidcsession.AccessTokenRevokedType, + oidcsession.RefreshTokenRevokedType, + ). + Builder() +} + +func (wm *OIDCSessionAccessTokenReadModel) reduceAdded(e *oidcsession.AddedEvent) { + wm.UserID = e.UserID + wm.SessionID = e.SessionID + wm.ClientID = e.ClientID + wm.Audience = e.Audience + wm.Scope = e.Scope + wm.AuthMethods = e.AuthMethods + wm.AuthTime = e.AuthTime + wm.State = domain.OIDCSessionStateActive +} + +func (wm *OIDCSessionAccessTokenReadModel) reduceAccessTokenAdded(e *oidcsession.AccessTokenAddedEvent) { + wm.AccessTokenID = e.ID + wm.AccessTokenCreation = e.CreationDate() + wm.AccessTokenExpiration = e.CreationDate().Add(e.Lifetime) +} + +func (wm *OIDCSessionAccessTokenReadModel) reduceTokenRevoked(e eventstore.Event) { + wm.AccessTokenID = "" + wm.AccessTokenExpiration = e.CreationDate() +} + +// ActiveAccessTokenByToken will check if the token is active by retrieving the OIDCSession events from the eventstore. +// Refreshed or expired tokens will return an error as well as if the underlying sessions has been terminated. +func (q *Queries) ActiveAccessTokenByToken(ctx context.Context, token string) (model *OIDCSessionAccessTokenReadModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + split := strings.Split(token, "-") + if len(split) != 2 { + return nil, caos_errs.ThrowPermissionDenied(nil, "QUERY-LJK2W", "Errors.OIDCSession.Token.Invalid") + } + model, err = q.accessTokenByOIDCSessionAndTokenID(ctx, split[0], split[1]) + if err != nil { + return nil, err + } + if !model.AccessTokenExpiration.After(time.Now()) { + return nil, caos_errs.ThrowPermissionDenied(nil, "QUERY-SAF3rf", "Errors.OIDCSession.Token.Expired") + } + if err = q.checkSessionNotTerminatedAfter(ctx, model.SessionID, model.AccessTokenCreation); err != nil { + return nil, err + } + return model, nil +} + +func (q *Queries) accessTokenByOIDCSessionAndTokenID(ctx context.Context, oidcSessionID, tokenID string) (model *OIDCSessionAccessTokenReadModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + model = newOIDCSessionAccessTokenReadModel(oidcSessionID) + if err = q.eventstore.FilterToQueryReducer(ctx, model); err != nil { + return nil, caos_errs.ThrowPermissionDenied(err, "QUERY-ASfe2", "Errors.OIDCSession.Token.Invalid") + } + if model.AccessTokenID != tokenID { + return nil, caos_errs.ThrowPermissionDenied(nil, "QUERY-M2u9w", "Errors.OIDCSession.Token.Invalid") + } + return model, nil +} + +// checkSessionNotTerminatedAfter checks if a [session.TerminateType] event occurred after a certain time +// and will return an error if so. +func (q *Queries) checkSessionNotTerminatedAfter(ctx context.Context, sessionID string, creation time.Time) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + events, err := q.eventstore.Filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AllowTimeTravel(). + AddQuery(). + AggregateTypes(session.AggregateType). + AggregateIDs(sessionID). + EventTypes( + session.TerminateType, + ). + CreationDateAfter(creation). + Builder()) + if err != nil { + return caos_errs.ThrowPermissionDenied(err, "QUERY-SJ642", "Errors.Internal") + } + if len(events) > 0 { + return caos_errs.ThrowPermissionDenied(nil, "QUERY-IJL3H", "Errors.OIDCSession.Token.Invalid") + } + return nil +} diff --git a/internal/query/app.go b/internal/query/app.go index 6b40f712e..577f6c181 100644 --- a/internal/query/app.go +++ b/internal/query/app.go @@ -253,7 +253,7 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bo defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.AppProjection.Trigger(ctx) + ctx = projection.AppProjection.Trigger(ctx) } stmt, scan := prepareAppQuery(ctx, q.client) diff --git a/internal/query/auth_request.go b/internal/query/auth_request.go new file mode 100644 index 000000000..ee91bdebe --- /dev/null +++ b/internal/query/auth_request.go @@ -0,0 +1,88 @@ +package query + +import ( + "context" + "database/sql" + _ "embed" + errs "errors" + "fmt" + "time" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/call" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/query/projection" + "github.com/zitadel/zitadel/internal/telemetry/tracing" +) + +type AuthRequest struct { + ID string + CreationDate time.Time + LoginClient string + ClientID string + Scope []string + RedirectURI string + Prompt []domain.Prompt + UiLocales []string + LoginHint *string + MaxAge *time.Duration + HintUserID *string +} + +func (a *AuthRequest) checkLoginClient(ctx context.Context) error { + if uid := authz.GetCtxData(ctx).UserID; uid != a.LoginClient { + return errors.ThrowPermissionDenied(nil, "OIDCv2-aL0ag", "Errors.AuthRequest.WrongLoginClient") + } + return nil +} + +//go:embed embed/auth_request_by_id.sql +var authRequestByIDQuery string + +func (q *Queries) authRequestByIDQuery(ctx context.Context) string { + return fmt.Sprintf(authRequestByIDQuery, q.client.Timetravel(call.Took(ctx))) +} + +func (q *Queries) AuthRequestByID(ctx context.Context, shouldTriggerBulk bool, id string, checkLoginClient bool) (_ *AuthRequest, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + if shouldTriggerBulk { + ctx = projection.AuthRequestProjection.Trigger(ctx) + } + + var ( + scope database.StringArray + prompt database.EnumArray[domain.Prompt] + locales database.StringArray + ) + + dst := new(AuthRequest) + err = q.client.DB.QueryRowContext( + ctx, q.authRequestByIDQuery(ctx), + id, authz.GetInstance(ctx).InstanceID(), + ).Scan( + &dst.ID, &dst.CreationDate, &dst.LoginClient, &dst.ClientID, &scope, &dst.RedirectURI, + &prompt, &locales, &dst.LoginHint, &dst.MaxAge, &dst.HintUserID, + ) + if errs.Is(err, sql.ErrNoRows) { + return nil, errors.ThrowNotFound(err, "QUERY-Thee9", "Errors.AuthRequest.NotExisting") + } + if err != nil { + return nil, errors.ThrowInternal(err, "QUERY-Ou8ue", "Errors.Internal") + } + + dst.Scope = scope + dst.Prompt = prompt + dst.UiLocales = locales + + if checkLoginClient { + if err = dst.checkLoginClient(ctx); err != nil { + return nil, err + } + } + + return dst, nil +} diff --git a/internal/query/auth_request_test.go b/internal/query/auth_request_test.go new file mode 100644 index 000000000..7348855e7 --- /dev/null +++ b/internal/query/auth_request_test.go @@ -0,0 +1,180 @@ +package query + +import ( + "database/sql" + "database/sql/driver" + _ "embed" + "fmt" + "regexp" + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/query/projection" +) + +func TestQueries_AuthRequestByID(t *testing.T) { + expQuery := regexp.QuoteMeta(fmt.Sprintf( + authRequestByIDQuery, + asOfSystemTime, + )) + + cols := []string{ + projection.AuthRequestColumnID, + projection.AuthRequestColumnCreationDate, + projection.AuthRequestColumnLoginClient, + projection.AuthRequestColumnClientID, + projection.AuthRequestColumnScope, + projection.AuthRequestColumnRedirectURI, + projection.AuthRequestColumnPrompt, + projection.AuthRequestColumnUILocales, + projection.AuthRequestColumnLoginHint, + projection.AuthRequestColumnMaxAge, + projection.AuthRequestColumnHintUserID, + } + type args struct { + shouldTriggerBulk bool + id string + checkLoginClient bool + } + tests := []struct { + name string + args args + expect sqlExpectation + want *AuthRequest + wantErr error + }{ + { + name: "success, all values", + args: args{ + shouldTriggerBulk: false, + id: "123", + checkLoginClient: true, + }, + expect: mockQuery(expQuery, cols, []driver.Value{ + "id", + testNow, + "loginClient", + "clientID", + database.StringArray{"a", "b", "c"}, + "example.com", + database.EnumArray[domain.Prompt]{domain.PromptLogin, domain.PromptConsent}, + database.StringArray{"en", "fi"}, + "me@example.com", + int64(time.Minute), + "userID", + }, "123", "instanceID"), + want: &AuthRequest{ + ID: "id", + CreationDate: testNow, + LoginClient: "loginClient", + ClientID: "clientID", + Scope: []string{"a", "b", "c"}, + RedirectURI: "example.com", + Prompt: []domain.Prompt{domain.PromptLogin, domain.PromptConsent}, + UiLocales: []string{"en", "fi"}, + LoginHint: gu.Ptr("me@example.com"), + MaxAge: gu.Ptr(time.Minute), + HintUserID: gu.Ptr("userID"), + }, + }, + { + name: "success, null values", + args: args{ + shouldTriggerBulk: false, + id: "123", + checkLoginClient: true, + }, + expect: mockQuery(expQuery, cols, []driver.Value{ + "id", + testNow, + "loginClient", + "clientID", + database.StringArray{"a", "b", "c"}, + "example.com", + database.EnumArray[domain.Prompt]{domain.PromptLogin, domain.PromptConsent}, + database.StringArray{"en", "fi"}, + sql.NullString{}, + sql.NullInt64{}, + sql.NullString{}, + }, "123", "instanceID"), + want: &AuthRequest{ + ID: "id", + CreationDate: testNow, + LoginClient: "loginClient", + ClientID: "clientID", + Scope: []string{"a", "b", "c"}, + RedirectURI: "example.com", + Prompt: []domain.Prompt{domain.PromptLogin, domain.PromptConsent}, + UiLocales: []string{"en", "fi"}, + LoginHint: nil, + MaxAge: nil, + HintUserID: nil, + }, + }, + { + name: "no rows", + args: args{ + shouldTriggerBulk: false, + id: "123", + }, + expect: mockQuery(expQuery, cols, nil, "123", "instanceID"), + wantErr: errors.ThrowNotFound(sql.ErrNoRows, "QUERY-Thee9", "Errors.AuthRequest.NotExisting"), + }, + { + name: "query error", + args: args{ + shouldTriggerBulk: false, + id: "123", + }, + expect: mockQueryErr(expQuery, sql.ErrConnDone, "123", "instanceID"), + wantErr: errors.ThrowInternal(sql.ErrConnDone, "QUERY-Ou8ue", "Errors.Internal"), + }, + { + name: "wrong login client", + args: args{ + shouldTriggerBulk: false, + id: "123", + checkLoginClient: true, + }, + expect: mockQuery(expQuery, cols, []driver.Value{ + "id", + testNow, + "wrongLoginClient", + "clientID", + database.StringArray{"a", "b", "c"}, + "example.com", + database.EnumArray[domain.Prompt]{domain.PromptLogin, domain.PromptConsent}, + database.StringArray{"en", "fi"}, + sql.NullString{}, + sql.NullInt64{}, + sql.NullString{}, + }, "123", "instanceID"), + wantErr: errors.ThrowPermissionDeniedf(nil, "OIDCv2-aL0ag", "Errors.AuthRequest.WrongLoginClient"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + execMock(t, tt.expect, func(db *sql.DB) { + q := &Queries{ + client: &database.DB{ + DB: db, + Database: &prepareDB{}, + }, + } + ctx := authz.NewMockContext("instanceID", "orgID", "loginClient") + + got, err := q.AuthRequestByID(ctx, tt.args.shouldTriggerBulk, tt.args.id, tt.args.checkLoginClient) + require.ErrorIs(t, err, tt.wantErr) + assert.Equal(t, tt.want, got) + }) + }) + } +} diff --git a/internal/query/authn_key.go b/internal/query/authn_key.go index 3d9341c94..87140b216 100644 --- a/internal/query/authn_key.go +++ b/internal/query/authn_key.go @@ -191,7 +191,7 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, i defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.AuthNKeyProjection.Trigger(ctx) + ctx = projection.AuthNKeyProjection.Trigger(ctx) } query, scan := prepareAuthNKeyQuery(ctx, q.client) diff --git a/internal/query/domain_policy.go b/internal/query/domain_policy.go index f9f5f94b7..2f7a596cd 100644 --- a/internal/query/domain_policy.go +++ b/internal/query/domain_policy.go @@ -91,7 +91,7 @@ func (q *Queries) DomainPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.DomainPolicyProjection.Trigger(ctx) + ctx = projection.DomainPolicyProjection.Trigger(ctx) } eq := sq.And{ sq.Eq{DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, diff --git a/internal/query/embed/auth_request_by_id.sql b/internal/query/embed/auth_request_by_id.sql new file mode 100644 index 000000000..ffc18fccd --- /dev/null +++ b/internal/query/embed/auth_request_by_id.sql @@ -0,0 +1,15 @@ +select + id, + creation_date, + login_client, + client_id, + scope, + redirect_uri, + prompt, + ui_locales, + login_hint, + max_age, + hint_user_id +from projections.auth_requests %s +where id = $1 and instance_id = $2 +limit 1; diff --git a/internal/query/idp.go b/internal/query/idp.go index e483755c8..35c0b7b5d 100644 --- a/internal/query/idp.go +++ b/internal/query/idp.go @@ -193,7 +193,7 @@ func (q *Queries) IDPByIDAndResourceOwner(ctx context.Context, shouldTriggerBulk defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.IDPProjection.Trigger(ctx) + ctx = projection.IDPProjection.Trigger(ctx) } eq := sq.Eq{ diff --git a/internal/query/idp_login_policy_link_test.go b/internal/query/idp_login_policy_link_test.go index 530780160..22f07e7fa 100644 --- a/internal/query/idp_login_policy_link_test.go +++ b/internal/query/idp_login_policy_link_test.go @@ -22,7 +22,7 @@ var ( ` COUNT(*) OVER ()` + ` FROM projections.idp_login_policy_links5` + ` LEFT JOIN projections.idp_templates5 ON projections.idp_login_policy_links5.idp_id = projections.idp_templates5.id AND projections.idp_login_policy_links5.instance_id = projections.idp_templates5.instance_id` + - ` RIGHT JOIN (SELECT login_policy_owner.aggregate_id, login_policy_owner.instance_id, login_policy_owner.owner_removed FROM projections.login_policies4 AS login_policy_owner` + + ` RIGHT JOIN (SELECT login_policy_owner.aggregate_id, login_policy_owner.instance_id, login_policy_owner.owner_removed FROM projections.login_policies5 AS login_policy_owner` + ` WHERE (login_policy_owner.instance_id = $1 AND (login_policy_owner.aggregate_id = $2 OR login_policy_owner.aggregate_id = $3)) ORDER BY login_policy_owner.is_default LIMIT 1) AS login_policy_owner` + ` ON login_policy_owner.aggregate_id = projections.idp_login_policy_links5.resource_owner AND login_policy_owner.instance_id = projections.idp_login_policy_links5.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) diff --git a/internal/query/idp_template.go b/internal/query/idp_template.go index 2639691a7..b83efe156 100644 --- a/internal/query/idp_template.go +++ b/internal/query/idp_template.go @@ -7,7 +7,6 @@ import ( "time" sq "github.com/Masterminds/squirrel" - "github.com/zitadel/logging" "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/call" @@ -612,8 +611,7 @@ func (q *Queries) IDPTemplateByID(ctx context.Context, shouldTriggerBulk bool, i defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - err := projection.IDPTemplateProjection.Trigger(ctx) - logging.OnError(err).WithField("projection", idpTemplateTable.identifier()).Warn("could not trigger projection for query") + ctx = projection.IDPTemplateProjection.Trigger(ctx) } eq := sq.Eq{ diff --git a/internal/query/instance.go b/internal/query/instance.go index 2b4cfb185..9040478af 100644 --- a/internal/query/instance.go +++ b/internal/query/instance.go @@ -182,7 +182,7 @@ func (q *Queries) Instance(ctx context.Context, shouldTriggerBulk bool) (_ *Inst defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.InstanceProjection.Trigger(ctx) + ctx = projection.InstanceProjection.Trigger(ctx) } stmt, scan := prepareInstanceDomainQuery(ctx, q.client, authz.GetInstance(ctx).RequestedDomain()) diff --git a/internal/query/lockout_policy.go b/internal/query/lockout_policy.go index 84b0e27ee..ff9dfc663 100644 --- a/internal/query/lockout_policy.go +++ b/internal/query/lockout_policy.go @@ -86,7 +86,7 @@ func (q *Queries) LockoutPolicyByOrg(ctx context.Context, shouldTriggerBulk bool defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.LockoutPolicyProjection.Trigger(ctx) + ctx = projection.LockoutPolicyProjection.Trigger(ctx) } eq := sq.Eq{ LockoutColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), diff --git a/internal/query/login_policy.go b/internal/query/login_policy.go index d575a26d3..dcf168d94 100644 --- a/internal/query/login_policy.go +++ b/internal/query/login_policy.go @@ -26,6 +26,7 @@ type LoginPolicy struct { AllowUsernamePassword bool AllowExternalIDPs bool ForceMFA bool + ForceMFALocalOnly bool SecondFactors database.EnumArray[domain.SecondFactorType] MultiFactors database.EnumArray[domain.MultiFactorType] PasswordlessType domain.PasswordlessType @@ -95,6 +96,10 @@ var ( name: projection.LoginPolicyForceMFACol, table: loginPolicyTable, } + LoginPolicyColumnForceMFALocalOnly = Column{ + name: projection.LoginPolicyForceMFALocalOnlyCol, + table: loginPolicyTable, + } LoginPolicyColumnSecondFactors = Column{ name: projection.LoginPolicy2FAsCol, table: loginPolicyTable, @@ -166,7 +171,7 @@ func (q *Queries) LoginPolicyByID(ctx context.Context, shouldTriggerBulk bool, o defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.LoginPolicyProjection.Trigger(ctx) + ctx = projection.LoginPolicyProjection.Trigger(ctx) } eq := sq.Eq{LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} if !withOwnerRemoved { @@ -351,6 +356,7 @@ func prepareLoginPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Select LoginPolicyColumnAllowUsernamePassword.identifier(), LoginPolicyColumnAllowExternalIDPs.identifier(), LoginPolicyColumnForceMFA.identifier(), + LoginPolicyColumnForceMFALocalOnly.identifier(), LoginPolicyColumnSecondFactors.identifier(), LoginPolicyColumnMultiFactors.identifier(), LoginPolicyColumnPasswordlessType.identifier(), @@ -381,6 +387,7 @@ func prepareLoginPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Select &p.AllowUsernamePassword, &p.AllowExternalIDPs, &p.ForceMFA, + &p.ForceMFALocalOnly, &p.SecondFactors, &p.MultiFactors, &p.PasswordlessType, diff --git a/internal/query/login_policy_test.go b/internal/query/login_policy_test.go index 144545633..2e1900f21 100644 --- a/internal/query/login_policy_test.go +++ b/internal/query/login_policy_test.go @@ -15,30 +15,31 @@ import ( ) var ( - loginPolicyQuery = `SELECT projections.login_policies4.aggregate_id,` + - ` projections.login_policies4.creation_date,` + - ` projections.login_policies4.change_date,` + - ` projections.login_policies4.sequence,` + - ` projections.login_policies4.allow_register,` + - ` projections.login_policies4.allow_username_password,` + - ` projections.login_policies4.allow_external_idps,` + - ` projections.login_policies4.force_mfa,` + - ` projections.login_policies4.second_factors,` + - ` projections.login_policies4.multi_factors,` + - ` projections.login_policies4.passwordless_type,` + - ` projections.login_policies4.is_default,` + - ` projections.login_policies4.hide_password_reset,` + - ` projections.login_policies4.ignore_unknown_usernames,` + - ` projections.login_policies4.allow_domain_discovery,` + - ` projections.login_policies4.disable_login_with_email,` + - ` projections.login_policies4.disable_login_with_phone,` + - ` projections.login_policies4.default_redirect_uri,` + - ` projections.login_policies4.password_check_lifetime,` + - ` projections.login_policies4.external_login_check_lifetime,` + - ` projections.login_policies4.mfa_init_skip_lifetime,` + - ` projections.login_policies4.second_factor_check_lifetime,` + - ` projections.login_policies4.multi_factor_check_lifetime` + - ` FROM projections.login_policies4` + + loginPolicyQuery = `SELECT projections.login_policies5.aggregate_id,` + + ` projections.login_policies5.creation_date,` + + ` projections.login_policies5.change_date,` + + ` projections.login_policies5.sequence,` + + ` projections.login_policies5.allow_register,` + + ` projections.login_policies5.allow_username_password,` + + ` projections.login_policies5.allow_external_idps,` + + ` projections.login_policies5.force_mfa,` + + ` projections.login_policies5.force_mfa_local_only,` + + ` projections.login_policies5.second_factors,` + + ` projections.login_policies5.multi_factors,` + + ` projections.login_policies5.passwordless_type,` + + ` projections.login_policies5.is_default,` + + ` projections.login_policies5.hide_password_reset,` + + ` projections.login_policies5.ignore_unknown_usernames,` + + ` projections.login_policies5.allow_domain_discovery,` + + ` projections.login_policies5.disable_login_with_email,` + + ` projections.login_policies5.disable_login_with_phone,` + + ` projections.login_policies5.default_redirect_uri,` + + ` projections.login_policies5.password_check_lifetime,` + + ` projections.login_policies5.external_login_check_lifetime,` + + ` projections.login_policies5.mfa_init_skip_lifetime,` + + ` projections.login_policies5.second_factor_check_lifetime,` + + ` projections.login_policies5.multi_factor_check_lifetime` + + ` FROM projections.login_policies5` + ` AS OF SYSTEM TIME '-1 ms'` loginPolicyCols = []string{ "aggregate_id", @@ -49,6 +50,7 @@ var ( "allow_username_password", "allow_external_idps", "force_mfa", + "force_mfa_local_only", "second_factors", "multi_factors", "passwordless_type", @@ -66,15 +68,15 @@ var ( "multi_factor_check_lifetime", } - prepareLoginPolicy2FAsStmt = `SELECT projections.login_policies4.second_factors` + - ` FROM projections.login_policies4` + + prepareLoginPolicy2FAsStmt = `SELECT projections.login_policies5.second_factors` + + ` FROM projections.login_policies5` + ` AS OF SYSTEM TIME '-1 ms'` prepareLoginPolicy2FAsCols = []string{ "second_factors", } - prepareLoginPolicyMFAsStmt = `SELECT projections.login_policies4.multi_factors` + - ` FROM projections.login_policies4` + + prepareLoginPolicyMFAsStmt = `SELECT projections.login_policies5.multi_factors` + + ` FROM projections.login_policies5` + ` AS OF SYSTEM TIME '-1 ms'` prepareLoginPolicyMFAsCols = []string{ "multi_factors", @@ -126,6 +128,7 @@ func Test_LoginPolicyPrepares(t *testing.T) { true, true, true, + true, database.EnumArray[domain.SecondFactorType]{domain.SecondFactorTypeOTP}, database.EnumArray[domain.MultiFactorType]{domain.MultiFactorTypeU2FWithPIN}, domain.PasswordlessTypeAllowed, @@ -153,6 +156,7 @@ func Test_LoginPolicyPrepares(t *testing.T) { AllowUsernamePassword: true, AllowExternalIDPs: true, ForceMFA: true, + ForceMFALocalOnly: true, SecondFactors: database.EnumArray[domain.SecondFactorType]{domain.SecondFactorTypeOTP}, MultiFactors: database.EnumArray[domain.MultiFactorType]{domain.MultiFactorTypeU2FWithPIN}, PasswordlessType: domain.PasswordlessTypeAllowed, diff --git a/internal/query/milestone.go b/internal/query/milestone.go new file mode 100644 index 000000000..b4767495b --- /dev/null +++ b/internal/query/milestone.go @@ -0,0 +1,146 @@ +package query + +import ( + "context" + "database/sql" + "time" + + sq "github.com/Masterminds/squirrel" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/call" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/query/projection" + "github.com/zitadel/zitadel/internal/repository/milestone" + "github.com/zitadel/zitadel/internal/telemetry/tracing" +) + +type Milestones struct { + SearchResponse + Milestones []*Milestone +} + +type Milestone struct { + InstanceID string + Type milestone.Type + ReachedDate time.Time + PushedDate time.Time + PrimaryDomain string +} + +type MilestonesSearchQueries struct { + SearchRequest + Queries []SearchQuery +} + +func (q *MilestonesSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder { + query = q.SearchRequest.toQuery(query) + for _, q := range q.Queries { + query = q.toQuery(query) + } + return query +} + +var ( + milestonesTable = table{ + name: projection.MilestonesProjectionTable, + instanceIDCol: projection.MilestoneColumnInstanceID, + } + MilestoneInstanceIDColID = Column{ + name: projection.MilestoneColumnInstanceID, + table: milestonesTable, + } + MilestoneTypeColID = Column{ + name: projection.MilestoneColumnType, + table: milestonesTable, + } + MilestonePrimaryDomainColID = Column{ + name: projection.MilestoneColumnPrimaryDomain, + table: milestonesTable, + } + MilestoneReachedDateColID = Column{ + name: projection.MilestoneColumnReachedDate, + table: milestonesTable, + } + MilestonePushedDateColID = Column{ + name: projection.MilestoneColumnPushedDate, + table: milestonesTable, + } +) + +// SearchMilestones tries to defer the instanceID from the passed context if no instanceIDs are passed +func (q *Queries) SearchMilestones(ctx context.Context, instanceIDs []string, queries *MilestonesSearchQueries) (_ *Milestones, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + query, scan := prepareMilestonesQuery(ctx, q.client) + if len(instanceIDs) == 0 { + instanceIDs = []string{authz.GetInstance(ctx).InstanceID()} + } + stmt, args, err := queries.toQuery(query).Where(sq.Eq{MilestoneInstanceIDColID.identifier(): instanceIDs}).ToSql() + if err != nil { + return nil, errors.ThrowInternal(err, "QUERY-A9i5k", "Errors.Query.SQLStatement") + } + rows, err := q.client.QueryContext(ctx, stmt, args...) + if err != nil { + return nil, err + } + defer func() { + if closeErr := rows.Close(); closeErr != nil && err == nil { + err = errors.ThrowInternal(closeErr, "QUERY-CK9mI", "Errors.Query.CloseRows") + } + }() + milestones, err := scan(rows) + if err != nil { + return nil, err + } + if err = rows.Err(); err != nil { + return nil, errors.ThrowInternal(err, "QUERY-asLsI", "Errors.Internal") + } + milestones.LatestSequence, err = q.latestSequence(ctx, milestonesTable) + return milestones, err + +} + +func prepareMilestonesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Milestones, error)) { + return sq.Select( + MilestoneInstanceIDColID.identifier(), + MilestonePrimaryDomainColID.identifier(), + MilestoneReachedDateColID.identifier(), + MilestonePushedDateColID.identifier(), + MilestoneTypeColID.identifier(), + countColumn.identifier(), + ). + From(milestonesTable.identifier() + db.Timetravel(call.Took(ctx))). + PlaceholderFormat(sq.Dollar), + func(rows *sql.Rows) (*Milestones, error) { + milestones := make([]*Milestone, 0) + var count uint64 + for rows.Next() { + m := new(Milestone) + reachedDate := sql.NullTime{} + pushedDate := sql.NullTime{} + primaryDomain := sql.NullString{} + err := rows.Scan( + &m.InstanceID, + &primaryDomain, + &reachedDate, + &pushedDate, + &m.Type, + &count, + ) + if err != nil { + return nil, err + } + m.PrimaryDomain = primaryDomain.String + m.ReachedDate = reachedDate.Time + m.PushedDate = pushedDate.Time + milestones = append(milestones, m) + } + return &Milestones{ + Milestones: milestones, + SearchResponse: SearchResponse{ + Count: count, + }, + }, nil + } +} diff --git a/internal/query/milestone_test.go b/internal/query/milestone_test.go new file mode 100644 index 000000000..1c1852a59 --- /dev/null +++ b/internal/query/milestone_test.go @@ -0,0 +1,189 @@ +package query + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "regexp" + "testing" +) + +var ( + expectedMilestoneQuery = regexp.QuoteMeta(` + SELECT projections.milestones.instance_id, + projections.milestones.primary_domain, + projections.milestones.reached_date, + projections.milestones.last_pushed_date, + projections.milestones.type, + COUNT(*) OVER () + FROM projections.milestones AS OF SYSTEM TIME '-1 ms' + `) + + milestoneCols = []string{ + "instance_id", + "primary_domain", + "reached_date", + "last_pushed_date", + "type", + "ignore_client_ids", + } +) + +func Test_MilestonesPrepare(t *testing.T) { + type want struct { + sqlExpectations sqlExpectation + err checkErr + } + tests := []struct { + name string + prepare interface{} + want want + object interface{} + }{ + { + name: "prepareMilestonesQuery no result", + prepare: prepareMilestonesQuery, + want: want{ + sqlExpectations: mockQueries( + expectedMilestoneQuery, + nil, + nil, + ), + }, + object: &Milestones{Milestones: []*Milestone{}}, + }, + { + name: "prepareMilestonesQuery", + prepare: prepareMilestonesQuery, + want: want{ + sqlExpectations: mockQueries( + expectedMilestoneQuery, + milestoneCols, + [][]driver.Value{ + { + "instance-id", + "primary.domain", + testNow, + testNow, + 1, + 1, + }, + }, + ), + }, + object: &Milestones{ + SearchResponse: SearchResponse{ + Count: 1, + }, + Milestones: []*Milestone{ + { + InstanceID: "instance-id", + Type: 1, + ReachedDate: testNow, + PushedDate: testNow, + PrimaryDomain: "primary.domain", + }, + }, + }, + }, + { + name: "prepareMilestonesQuery multiple result", + prepare: prepareMilestonesQuery, + want: want{ + sqlExpectations: mockQueries( + expectedMilestoneQuery, + milestoneCols, + [][]driver.Value{ + { + "instance-id", + "primary.domain", + testNow, + testNow, + 1, + 1, + }, + { + "instance-id", + "primary.domain", + testNow, + testNow, + 2, + 2, + }, + { + "instance-id", + "primary.domain", + testNow, + nil, + 3, + 3, + }, + { + "instance-id", + "primary.domain", + nil, + nil, + 4, + 4, + }, + }, + ), + }, + object: &Milestones{ + SearchResponse: SearchResponse{ + Count: 4, + }, + Milestones: []*Milestone{ + { + InstanceID: "instance-id", + Type: 1, + ReachedDate: testNow, + PushedDate: testNow, + PrimaryDomain: "primary.domain", + }, + { + InstanceID: "instance-id", + Type: 2, + ReachedDate: testNow, + PushedDate: testNow, + PrimaryDomain: "primary.domain", + }, + { + InstanceID: "instance-id", + Type: 3, + ReachedDate: testNow, + PrimaryDomain: "primary.domain", + }, + { + InstanceID: "instance-id", + Type: 4, + PrimaryDomain: "primary.domain", + }, + }, + }, + }, + { + name: "prepareMilestonesQuery sql err", + prepare: prepareMilestonesQuery, + want: want{ + sqlExpectations: mockQueryErr( + expectedMilestoneQuery, + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...) + }) + } +} diff --git a/internal/query/notification_policy.go b/internal/query/notification_policy.go index e15e7c84f..64873e1ca 100644 --- a/internal/query/notification_policy.go +++ b/internal/query/notification_policy.go @@ -81,7 +81,8 @@ func (q *Queries) NotificationPolicyByOrg(ctx context.Context, shouldTriggerBulk defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - if err := projection.NotificationPolicyProjection.Trigger(ctx); err != nil { + ctx, err = projection.NotificationPolicyProjection.TriggerErr(ctx) + if err != nil { return nil, err } } @@ -112,7 +113,8 @@ func (q *Queries) DefaultNotificationPolicy(ctx context.Context, shouldTriggerBu defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - if err := projection.NotificationPolicyProjection.Trigger(ctx); err != nil { + ctx, err = projection.NotificationPolicyProjection.TriggerErr(ctx) + if err != nil { return nil, err } } diff --git a/internal/query/org.go b/internal/query/org.go index d5c90f08f..40bcbe400 100644 --- a/internal/query/org.go +++ b/internal/query/org.go @@ -94,7 +94,7 @@ func (q *Queries) OrgByID(ctx context.Context, shouldTriggerBulk bool, id string defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.OrgProjection.Trigger(ctx) + ctx = projection.OrgProjection.Trigger(ctx) } stmt, scan := prepareOrgQuery(ctx, q.client) diff --git a/internal/query/org_metadata.go b/internal/query/org_metadata.go index c22bd6a71..5ce36369e 100644 --- a/internal/query/org_metadata.go +++ b/internal/query/org_metadata.go @@ -82,7 +82,7 @@ func (q *Queries) GetOrgMetadataByKey(ctx context.Context, shouldTriggerBulk boo defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.OrgMetadataProjection.Trigger(ctx) + ctx = projection.OrgMetadataProjection.Trigger(ctx) } query, scan := prepareOrgMetadataQuery(ctx, q.client) @@ -111,7 +111,7 @@ func (q *Queries) SearchOrgMetadata(ctx context.Context, shouldTriggerBulk bool, defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.OrgMetadataProjection.Trigger(ctx) + ctx = projection.OrgMetadataProjection.Trigger(ctx) } eq := sq.Eq{ OrgMetadataOrgIDCol.identifier(): orgID, diff --git a/internal/query/password_age_policy.go b/internal/query/password_age_policy.go index 2de71235a..fda59e88e 100644 --- a/internal/query/password_age_policy.go +++ b/internal/query/password_age_policy.go @@ -86,7 +86,7 @@ func (q *Queries) PasswordAgePolicyByOrg(ctx context.Context, shouldTriggerBulk defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PasswordAgeProjection.Trigger(ctx) + ctx = projection.PasswordAgeProjection.Trigger(ctx) } eq := sq.Eq{PasswordAgeColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} if !withOwnerRemoved { @@ -116,7 +116,7 @@ func (q *Queries) DefaultPasswordAgePolicy(ctx context.Context, shouldTriggerBul defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PasswordAgeProjection.Trigger(ctx) + ctx = projection.PasswordAgeProjection.Trigger(ctx) } stmt, scan := preparePasswordAgePolicyQuery(ctx, q.client) diff --git a/internal/query/password_complexity_policy.go b/internal/query/password_complexity_policy.go index 4877f0159..e5f15f181 100644 --- a/internal/query/password_complexity_policy.go +++ b/internal/query/password_complexity_policy.go @@ -38,7 +38,7 @@ func (q *Queries) PasswordComplexityPolicyByOrg(ctx context.Context, shouldTrigg defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PasswordComplexityProjection.Trigger(ctx) + ctx = projection.PasswordComplexityProjection.Trigger(ctx) } eq := sq.Eq{PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} if !withOwnerRemoved { @@ -68,7 +68,7 @@ func (q *Queries) DefaultPasswordComplexityPolicy(ctx context.Context, shouldTri defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PasswordComplexityProjection.Trigger(ctx) + ctx = projection.PasswordComplexityProjection.Trigger(ctx) } stmt, scan := preparePasswordComplexityPolicyQuery(ctx, q.client) diff --git a/internal/query/prepare_test.go b/internal/query/prepare_test.go index db309805c..cb69fb21e 100644 --- a/internal/query/prepare_test.go +++ b/internal/query/prepare_test.go @@ -14,6 +14,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" sq "github.com/Masterminds/squirrel" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var ( @@ -74,9 +75,9 @@ type checkErr func(error) (err error, ok bool) type sqlExpectation func(sqlmock.Sqlmock) sqlmock.Sqlmock -func mockQuery(stmt string, cols []string, row []driver.Value) func(m sqlmock.Sqlmock) sqlmock.Sqlmock { +func mockQuery(stmt string, cols []string, row []driver.Value, args ...driver.Value) func(m sqlmock.Sqlmock) sqlmock.Sqlmock { return func(m sqlmock.Sqlmock) sqlmock.Sqlmock { - q := m.ExpectQuery(stmt) + q := m.ExpectQuery(stmt).WithArgs(args...) result := sqlmock.NewRows(cols) if len(row) > 0 { result.AddRow(row...) @@ -111,6 +112,15 @@ func mockQueryErr(stmt string, err error, args ...driver.Value) func(m sqlmock.S } } +func execMock(t testing.TB, exp sqlExpectation, run func(db *sql.DB)) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + defer db.Close() + mock = exp(mock) + run(db) + assert.NoError(t, mock.ExpectationsWereMet()) +} + var ( rowType = reflect.TypeOf(&sql.Row{}) rowsType = reflect.TypeOf(&sql.Rows{}) @@ -317,7 +327,9 @@ func TestValidatePrepare(t *testing.T) { type prepareDB struct{} -func (_ *prepareDB) Timetravel(time.Duration) string { return " AS OF SYSTEM TIME '-1 ms' " } +const asOfSystemTime = " AS OF SYSTEM TIME '-1 ms' " + +func (*prepareDB) Timetravel(time.Duration) string { return asOfSystemTime } var defaultPrepareArgs = []reflect.Value{reflect.ValueOf(context.Background()), reflect.ValueOf(new(prepareDB))} diff --git a/internal/query/privacy_policy.go b/internal/query/privacy_policy.go index 2874c6d22..e207c3e9b 100644 --- a/internal/query/privacy_policy.go +++ b/internal/query/privacy_policy.go @@ -96,7 +96,7 @@ func (q *Queries) PrivacyPolicyByOrg(ctx context.Context, shouldTriggerBulk bool defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PrivacyPolicyProjection.Trigger(ctx) + ctx = projection.PrivacyPolicyProjection.Trigger(ctx) } eq := sq.Eq{PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} if !withOwnerRemoved { @@ -125,7 +125,7 @@ func (q *Queries) DefaultPrivacyPolicy(ctx context.Context, shouldTriggerBulk bo defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PrivacyPolicyProjection.Trigger(ctx) + ctx = projection.PrivacyPolicyProjection.Trigger(ctx) } stmt, scan := preparePrivacyPolicyQuery(ctx, q.client) diff --git a/internal/query/project.go b/internal/query/project.go index e7df58cf5..065a3e5c5 100644 --- a/internal/query/project.go +++ b/internal/query/project.go @@ -105,7 +105,7 @@ func (q *Queries) ProjectByID(ctx context.Context, shouldTriggerBulk bool, id st defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.ProjectProjection.Trigger(ctx) + ctx = projection.ProjectProjection.Trigger(ctx) } stmt, scan := prepareProjectQuery(ctx, q.client) diff --git a/internal/query/project_grant.go b/internal/query/project_grant.go index bbf265736..fee8ae836 100644 --- a/internal/query/project_grant.go +++ b/internal/query/project_grant.go @@ -116,7 +116,7 @@ func (q *Queries) ProjectGrantByID(ctx context.Context, shouldTriggerBulk bool, defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.ProjectGrantProjection.Trigger(ctx) + ctx = projection.ProjectGrantProjection.Trigger(ctx) } stmt, scan := prepareProjectGrantQuery(ctx, q.client) diff --git a/internal/query/project_role.go b/internal/query/project_role.go index 03ebbf60b..7365b1247 100644 --- a/internal/query/project_role.go +++ b/internal/query/project_role.go @@ -88,7 +88,7 @@ func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.ProjectRoleProjection.Trigger(ctx) + ctx = projection.ProjectRoleProjection.Trigger(ctx) } eq := sq.Eq{ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} diff --git a/internal/query/projection/assert.go b/internal/query/projection/assert.go new file mode 100644 index 000000000..369a6da69 --- /dev/null +++ b/internal/query/projection/assert.go @@ -0,0 +1,14 @@ +package projection + +import ( + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" +) + +func assertEvent[T eventstore.Event](event eventstore.Event) (T, error) { + e, ok := event.(T) + if !ok { + return e, errors.ThrowInvalidArgumentf(nil, "HANDL-1m9fS", "reduce.wrong.event.type %T", event) + } + return e, nil +} diff --git a/internal/query/projection/assert_test.go b/internal/query/projection/assert_test.go new file mode 100644 index 000000000..010f0c81a --- /dev/null +++ b/internal/query/projection/assert_test.go @@ -0,0 +1,52 @@ +package projection + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/instance" +) + +func Test_assertEvent(t *testing.T) { + type args struct { + event eventstore.Event + assertFunc func(eventstore.Event) (eventstore.Event, error) + } + type testCase struct { + name string + args args + wantErr assert.ErrorAssertionFunc + } + tests := []testCase{ + { + name: "correct event type", + args: args{ + event: instance.NewInstanceAddedEvent(context.Background(), &instance.NewAggregate("instance-id").Aggregate, "instance-name"), + assertFunc: func(event eventstore.Event) (eventstore.Event, error) { + return assertEvent[*instance.InstanceAddedEvent](event) + }, + }, + wantErr: assert.NoError, + }, { + name: "wrong event type", + args: args{ + event: instance.NewInstanceRemovedEvent(context.Background(), &instance.NewAggregate("instance-id").Aggregate, "instance-name", nil), + assertFunc: func(event eventstore.Event) (eventstore.Event, error) { + return assertEvent[*instance.InstanceAddedEvent](event) + }, + }, + wantErr: assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.args.assertFunc(tt.args.event) + if !tt.wantErr(t, err) { + return + } + }) + } +} diff --git a/internal/query/projection/auth_request.go b/internal/query/projection/auth_request.go new file mode 100644 index 000000000..b01ce175a --- /dev/null +++ b/internal/query/projection/auth_request.go @@ -0,0 +1,142 @@ +package projection + +import ( + "context" + + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/handler" + "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" + "github.com/zitadel/zitadel/internal/repository/authrequest" + "github.com/zitadel/zitadel/internal/repository/instance" +) + +const ( + AuthRequestsProjectionTable = "projections.auth_requests" + + AuthRequestColumnID = "id" + AuthRequestColumnCreationDate = "creation_date" + AuthRequestColumnChangeDate = "change_date" + AuthRequestColumnSequence = "sequence" + AuthRequestColumnResourceOwner = "resource_owner" + AuthRequestColumnInstanceID = "instance_id" + AuthRequestColumnLoginClient = "login_client" + AuthRequestColumnClientID = "client_id" + AuthRequestColumnRedirectURI = "redirect_uri" + AuthRequestColumnScope = "scope" + AuthRequestColumnPrompt = "prompt" + AuthRequestColumnUILocales = "ui_locales" + AuthRequestColumnMaxAge = "max_age" + AuthRequestColumnLoginHint = "login_hint" + AuthRequestColumnHintUserID = "hint_user_id" +) + +type authRequestProjection struct { + crdb.StatementHandler +} + +func newAuthRequestProjection(ctx context.Context, config crdb.StatementHandlerConfig) *authRequestProjection { + p := new(authRequestProjection) + config.ProjectionName = AuthRequestsProjectionTable + config.Reducers = p.reducers() + config.InitCheck = crdb.NewMultiTableCheck( + crdb.NewTable([]*crdb.Column{ + crdb.NewColumn(AuthRequestColumnID, crdb.ColumnTypeText), + crdb.NewColumn(AuthRequestColumnCreationDate, crdb.ColumnTypeTimestamp), + crdb.NewColumn(AuthRequestColumnChangeDate, crdb.ColumnTypeTimestamp), + crdb.NewColumn(AuthRequestColumnSequence, crdb.ColumnTypeInt64), + crdb.NewColumn(AuthRequestColumnResourceOwner, crdb.ColumnTypeText), + crdb.NewColumn(AuthRequestColumnInstanceID, crdb.ColumnTypeText), + crdb.NewColumn(AuthRequestColumnLoginClient, crdb.ColumnTypeText), + crdb.NewColumn(AuthRequestColumnClientID, crdb.ColumnTypeText), + crdb.NewColumn(AuthRequestColumnRedirectURI, crdb.ColumnTypeText), + crdb.NewColumn(AuthRequestColumnScope, crdb.ColumnTypeTextArray), + crdb.NewColumn(AuthRequestColumnPrompt, crdb.ColumnTypeEnumArray, crdb.Nullable()), + crdb.NewColumn(AuthRequestColumnUILocales, crdb.ColumnTypeTextArray, crdb.Nullable()), + crdb.NewColumn(AuthRequestColumnMaxAge, crdb.ColumnTypeInt64, crdb.Nullable()), + crdb.NewColumn(AuthRequestColumnLoginHint, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(AuthRequestColumnHintUserID, crdb.ColumnTypeText, crdb.Nullable()), + }, + crdb.NewPrimaryKey(AuthRequestColumnInstanceID, AuthRequestColumnID), + ), + ) + p.StatementHandler = crdb.NewStatementHandler(ctx, config) + return p +} + +func (p *authRequestProjection) reducers() []handler.AggregateReducer { + return []handler.AggregateReducer{ + { + Aggregate: authrequest.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: authrequest.AddedType, + Reduce: p.reduceAuthRequestAdded, + }, + { + Event: authrequest.SucceededType, + Reduce: p.reduceAuthRequestEnded, + }, + { + Event: authrequest.FailedType, + Reduce: p.reduceAuthRequestEnded, + }, + }, + }, + { + Aggregate: instance.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: instance.InstanceRemovedEventType, + Reduce: reduceInstanceRemovedHelper(AuthRequestColumnInstanceID), + }, + }, + }, + } +} + +func (p *authRequestProjection) reduceAuthRequestAdded(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*authrequest.AddedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Sfwfa", "reduce.wrong.event.type %s", authrequest.AddedType) + } + + return crdb.NewCreateStatement( + e, + []handler.Column{ + handler.NewCol(AuthRequestColumnID, e.Aggregate().ID), + handler.NewCol(AuthRequestColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCol(AuthRequestColumnCreationDate, e.CreationDate()), + handler.NewCol(AuthRequestColumnChangeDate, e.CreationDate()), + handler.NewCol(AuthRequestColumnResourceOwner, e.Aggregate().ResourceOwner), + handler.NewCol(AuthRequestColumnSequence, e.Sequence()), + handler.NewCol(AuthRequestColumnLoginClient, e.LoginClient), + handler.NewCol(AuthRequestColumnClientID, e.ClientID), + handler.NewCol(AuthRequestColumnRedirectURI, e.RedirectURI), + handler.NewCol(AuthRequestColumnScope, e.Scope), + handler.NewCol(AuthRequestColumnPrompt, e.Prompt), + handler.NewCol(AuthRequestColumnUILocales, e.UILocales), + handler.NewCol(AuthRequestColumnMaxAge, e.MaxAge), + handler.NewCol(AuthRequestColumnLoginHint, e.LoginHint), + handler.NewCol(AuthRequestColumnHintUserID, e.HintUserID), + }, + ), nil +} + +func (p *authRequestProjection) reduceAuthRequestEnded(event eventstore.Event) (*handler.Statement, error) { + switch event.(type) { + case *authrequest.SucceededEvent, + *authrequest.FailedEvent: + break + default: + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-ASF3h", "reduce.wrong.event.type %s", []eventstore.EventType{authrequest.SucceededType, authrequest.FailedType}) + } + + return crdb.NewDeleteStatement( + event, + []handler.Condition{ + handler.NewCond(AuthRequestColumnID, event.Aggregate().ID), + handler.NewCond(AuthRequestColumnInstanceID, event.Aggregate().InstanceID), + }, + ), nil +} diff --git a/internal/query/projection/auth_request_test.go b/internal/query/projection/auth_request_test.go new file mode 100644 index 000000000..f0ce0651d --- /dev/null +++ b/internal/query/projection/auth_request_test.go @@ -0,0 +1,134 @@ +package projection + +import ( + "testing" + "time" + + "github.com/muhlemmer/gu" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/handler" + "github.com/zitadel/zitadel/internal/repository/authrequest" +) + +func TestAuthRequestProjection_reduces(t *testing.T) { + type args struct { + event func(t *testing.T) eventstore.Event + } + tests := []struct { + name string + args args + reduce func(event eventstore.Event) (*handler.Statement, error) + want wantReduce + }{ + { + name: "reduceAuthRequestAdded", + args: args{ + event: getEvent(testEvent( + authrequest.AddedType, + authrequest.AggregateType, + []byte(`{"login_client": "loginClient", "client_id":"clientId","redirect_uri": "redirectURI", "scope": ["openid"], "prompt": [1], "ui_locales": ["en","de"], "max_age": 0, "login_hint": "loginHint", "hint_user_id": "hintUserID"}`), + ), authrequest.AddedEventMapper), + }, + reduce: (&authRequestProjection{}).reduceAuthRequestAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("auth_request"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "INSERT INTO projections.auth_requests (id, instance_id, creation_date, change_date, resource_owner, sequence, login_client, client_id, redirect_uri, scope, prompt, ui_locales, max_age, login_hint, hint_user_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)", + expectedArgs: []interface{}{ + "agg-id", + "instance-id", + anyArg{}, + anyArg{}, + "ro-id", + uint64(15), + "loginClient", + "clientId", + "redirectURI", + []string{"openid"}, + []domain.Prompt{domain.PromptNone}, + []string{"en", "de"}, + gu.Ptr(time.Duration(0)), + gu.Ptr("loginHint"), + gu.Ptr("hintUserID"), + }, + }, + }, + }, + }, + }, + { + name: "reduceAuthRequestFailed", + args: args{ + event: getEvent(testEvent( + authrequest.FailedType, + authrequest.AggregateType, + []byte(`{"reason": 0}`), + ), authrequest.FailedEventMapper), + }, + reduce: (&authRequestProjection{}).reduceAuthRequestEnded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("auth_request"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "DELETE FROM projections.auth_requests WHERE (id = $1) AND (instance_id = $2)", + expectedArgs: []interface{}{ + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, + { + name: "reduceAuthRequestSucceeded", + args: args{ + event: getEvent(testEvent( + authrequest.SucceededType, + authrequest.AggregateType, + nil, + ), authrequest.SucceededEventMapper), + }, + reduce: (&authRequestProjection{}).reduceAuthRequestEnded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("auth_request"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "DELETE FROM projections.auth_requests WHERE (id = $1) AND (instance_id = $2)", + expectedArgs: []interface{}{ + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + event := baseEvent(t) + got, err := tt.reduce(event) + if !errors.IsErrorInvalidArgument(err) { + t.Errorf("no wrong event mapping: %v, got: %v", err, got) + } + + event = tt.args.event(t) + got, err = tt.reduce(event) + assertReduce(t, got, err, AuthRequestsProjectionTable, tt.want) + }) + } +} diff --git a/internal/query/projection/event_test.go b/internal/query/projection/event_test.go index 29e32e95c..40dd2234e 100644 --- a/internal/query/projection/event_test.go +++ b/internal/query/projection/event_test.go @@ -14,12 +14,26 @@ func testEvent( eventType repository.EventType, aggregateType repository.AggregateType, data []byte, +) *repository.Event { + return timedTestEvent(eventType, aggregateType, data, time.Now()) +} + +func toSystemEvent(event *repository.Event) *repository.Event { + event.EditorService = "SYSTEM" + return event +} + +func timedTestEvent( + eventType repository.EventType, + aggregateType repository.AggregateType, + data []byte, + creationDate time.Time, ) *repository.Event { return &repository.Event{ Sequence: 15, PreviousAggregateSequence: 10, PreviousAggregateTypeSequence: 10, - CreationDate: time.Now(), + CreationDate: creationDate, Type: eventType, AggregateType: aggregateType, Data: data, diff --git a/internal/query/projection/label_policy.go b/internal/query/projection/label_policy.go index b8a84d922..e62c39b4c 100644 --- a/internal/query/projection/label_policy.go +++ b/internal/query/projection/label_policy.go @@ -402,10 +402,10 @@ func (p *labelPolicyProjection) reduceActivated(event eventstore.Event) (*handle handler.NewCol(LabelPolicyDarkLogoURLCol, nil), handler.NewCol(LabelPolicyDarkIconURLCol, nil), }, - []handler.Condition{ - handler.NewCond(LabelPolicyIDCol, event.Aggregate().ID), - handler.NewCond(LabelPolicyStateCol, domain.LabelPolicyStatePreview), - handler.NewCond(LabelPolicyInstanceIDCol, event.Aggregate().InstanceID), + []handler.NamespacedCondition{ + handler.NewNamespacedCondition(LabelPolicyIDCol, event.Aggregate().ID), + handler.NewNamespacedCondition(LabelPolicyStateCol, domain.LabelPolicyStatePreview), + handler.NewNamespacedCondition(LabelPolicyInstanceIDCol, event.Aggregate().InstanceID), }), nil } diff --git a/internal/query/projection/label_policy_test.go b/internal/query/projection/label_policy_test.go index f7190f6d5..88a82ea0c 100644 --- a/internal/query/projection/label_policy_test.go +++ b/internal/query/projection/label_policy_test.go @@ -170,7 +170,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE copy_table.id = $4 AND copy_table.state = $5 AND copy_table.instance_id = $6 ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", + expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE (copy_table.id = $4) AND (copy_table.state = $5) AND (copy_table.instance_id = $6) ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -631,7 +631,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE copy_table.id = $4 AND copy_table.state = $5 AND copy_table.instance_id = $6 ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", + expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE (copy_table.id = $4) AND (copy_table.state = $5) AND (copy_table.instance_id = $6) ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", expectedArgs: []interface{}{ anyArg{}, uint64(15), diff --git a/internal/query/projection/login_policy.go b/internal/query/projection/login_policy.go index 601a4531b..77fadc2ba 100644 --- a/internal/query/projection/login_policy.go +++ b/internal/query/projection/login_policy.go @@ -13,7 +13,7 @@ import ( ) const ( - LoginPolicyTable = "projections.login_policies4" + LoginPolicyTable = "projections.login_policies5" LoginPolicyIDCol = "aggregate_id" LoginPolicyInstanceIDCol = "instance_id" @@ -25,6 +25,7 @@ const ( LoginPolicyAllowUsernamePasswordCol = "allow_username_password" LoginPolicyAllowExternalIDPsCol = "allow_external_idps" LoginPolicyForceMFACol = "force_mfa" + LoginPolicyForceMFALocalOnlyCol = "force_mfa_local_only" LoginPolicy2FAsCol = "second_factors" LoginPolicyMFAsCol = "multi_factors" LoginPolicyPasswordlessTypeCol = "passwordless_type" @@ -62,6 +63,7 @@ func newLoginPolicyProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(LoginPolicyAllowUsernamePasswordCol, crdb.ColumnTypeBool), crdb.NewColumn(LoginPolicyAllowExternalIDPsCol, crdb.ColumnTypeBool), crdb.NewColumn(LoginPolicyForceMFACol, crdb.ColumnTypeBool), + crdb.NewColumn(LoginPolicyForceMFALocalOnlyCol, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(LoginPolicy2FAsCol, crdb.ColumnTypeEnumArray, crdb.Nullable()), crdb.NewColumn(LoginPolicyMFAsCol, crdb.ColumnTypeEnumArray, crdb.Nullable()), crdb.NewColumn(LoginPolicyPasswordlessTypeCol, crdb.ColumnTypeEnum), @@ -185,6 +187,7 @@ func (p *loginPolicyProjection) reduceLoginPolicyAdded(event eventstore.Event) ( handler.NewCol(LoginPolicyAllowUsernamePasswordCol, policyEvent.AllowUserNamePassword), handler.NewCol(LoginPolicyAllowExternalIDPsCol, policyEvent.AllowExternalIDP), handler.NewCol(LoginPolicyForceMFACol, policyEvent.ForceMFA), + handler.NewCol(LoginPolicyForceMFALocalOnlyCol, policyEvent.ForceMFALocalOnly), handler.NewCol(LoginPolicyPasswordlessTypeCol, policyEvent.PasswordlessType), handler.NewCol(LoginPolicyIsDefaultCol, isDefault), handler.NewCol(LoginPolicyHidePWResetCol, policyEvent.HidePasswordReset), @@ -228,6 +231,9 @@ func (p *loginPolicyProjection) reduceLoginPolicyChanged(event eventstore.Event) if policyEvent.ForceMFA != nil { cols = append(cols, handler.NewCol(LoginPolicyForceMFACol, *policyEvent.ForceMFA)) } + if policyEvent.ForceMFALocalOnly != nil { + cols = append(cols, handler.NewCol(LoginPolicyForceMFALocalOnlyCol, *policyEvent.ForceMFALocalOnly)) + } if policyEvent.PasswordlessType != nil { cols = append(cols, handler.NewCol(LoginPolicyPasswordlessTypeCol, *policyEvent.PasswordlessType)) } diff --git a/internal/query/projection/login_policy_test.go b/internal/query/projection/login_policy_test.go index 8ade083c0..bd87c5c4b 100644 --- a/internal/query/projection/login_policy_test.go +++ b/internal/query/projection/login_policy_test.go @@ -24,7 +24,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { want wantReduce }{ { - name: "org reduceLoginPolicyAdded", + name: "org reduceLoginPolicyAdded without forceMFALocalOnly", args: args{ event: getEvent(testEvent( repository.EventType(org.LoginPolicyAddedEventType), @@ -57,7 +57,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_policies4 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)", + expectedStmt: "INSERT INTO projections.login_policies5 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, force_mfa_local_only, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -68,6 +68,73 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { true, false, false, + false, + domain.PasswordlessTypeAllowed, + false, + true, + true, + true, + true, + true, + "https://example.com/redirect", + time.Millisecond * 10, + time.Millisecond * 10, + time.Millisecond * 10, + time.Millisecond * 10, + time.Millisecond * 10, + }, + }, + }, + }, + }, + }, + { + name: "org reduceLoginPolicyAdded", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.LoginPolicyAddedEventType), + org.AggregateType, + []byte(`{ + "allowUsernamePassword": true, + "allowRegister": true, + "allowExternalIdp": true, + "forceMFA": true, + "forceMFALocalOnly": true, + "hidePasswordReset": true, + "ignoreUnknownUsernames": true, + "allowDomainDiscovery": true, + "disableLoginWithEmail": true, + "disableLoginWithPhone": true, + "passwordlessType": 1, + "defaultRedirectURI": "https://example.com/redirect", + "passwordCheckLifetime": 10000000, + "externalLoginCheckLifetime": 10000000, + "mfaInitSkipLifetime": 10000000, + "secondFactorCheckLifetime": 10000000, + "multiFactorCheckLifetime": 10000000 + }`), + ), org.LoginPolicyAddedEventMapper), + }, + reduce: (&loginPolicyProjection{}).reduceLoginPolicyAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "INSERT INTO projections.login_policies5 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, force_mfa_local_only, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", + expectedArgs: []interface{}{ + "agg-id", + "instance-id", + anyArg{}, + anyArg{}, + uint64(15), + true, + true, + true, + true, + true, domain.PasswordlessTypeAllowed, false, true, @@ -99,6 +166,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { "allowRegister": true, "allowExternalIdp": true, "forceMFA": true, + "forceMFALocalOnly": true, "hidePasswordReset": true, "ignoreUnknownUsernames": true, "allowDomainDiscovery": true, @@ -121,7 +189,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) WHERE (aggregate_id = $19) AND (instance_id = $20)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, force_mfa_local_only, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) WHERE (aggregate_id = $20) AND (instance_id = $21)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -129,6 +197,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, true, true, @@ -168,7 +237,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -200,7 +269,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -230,7 +299,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_policies4 WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.login_policies5 WHERE (aggregate_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -259,7 +328,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -291,7 +360,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -314,8 +383,9 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { []byte(`{ "allowUsernamePassword": true, "allowRegister": true, - "allowExternalIdp": false, - "forceMFA": false, + "allowExternalIdp": true, + "forceMFA": true, + "forceMFALocalOnly": true, "hidePasswordReset": true, "ignoreUnknownUsernames": true, "allowDomainDiscovery": true, @@ -338,7 +408,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_policies4 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)", + expectedStmt: "INSERT INTO projections.login_policies5 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, force_mfa_local_only, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -347,8 +417,9 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { uint64(15), true, true, - false, - false, + true, + true, + true, domain.PasswordlessTypeAllowed, true, true, @@ -380,6 +451,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { "allowRegister": true, "allowExternalIdp": true, "forceMFA": true, + "forceMFALocalOnly": true, "hidePasswordReset": true, "ignoreUnknownUsernames": true, "allowDomainDiscovery": true, @@ -397,7 +469,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (aggregate_id = $14) AND (instance_id = $15)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, force_mfa_local_only, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) WHERE (aggregate_id = $15) AND (instance_id = $16)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -405,6 +477,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { true, true, true, + true, domain.PasswordlessTypeAllowed, true, true, @@ -439,7 +512,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -471,7 +544,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -503,7 +576,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -535,7 +608,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -565,7 +638,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5)", + expectedStmt: "UPDATE projections.login_policies5 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -595,7 +668,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_policies4 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.login_policies5 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/milestones.go b/internal/query/projection/milestones.go new file mode 100644 index 000000000..dbbf22a60 --- /dev/null +++ b/internal/query/projection/milestones.go @@ -0,0 +1,295 @@ +package projection + +import ( + "context" + "strconv" + "strings" + + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/handler" + "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" + "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/milestone" + "github.com/zitadel/zitadel/internal/repository/project" + "github.com/zitadel/zitadel/internal/repository/user" +) + +const ( + MilestonesProjectionTable = "projections.milestones" + + MilestoneColumnInstanceID = "instance_id" + MilestoneColumnType = "type" + MilestoneColumnPrimaryDomain = "primary_domain" + MilestoneColumnReachedDate = "reached_date" + MilestoneColumnPushedDate = "last_pushed_date" + MilestoneColumnIgnoreClientIDs = "ignore_client_ids" +) + +type milestoneProjection struct { + crdb.StatementHandler +} + +func newMilestoneProjection(ctx context.Context, config crdb.StatementHandlerConfig) *milestoneProjection { + p := new(milestoneProjection) + config.ProjectionName = MilestonesProjectionTable + config.Reducers = p.reducers() + config.InitCheck = crdb.NewMultiTableCheck( + crdb.NewTable([]*crdb.Column{ + crdb.NewColumn(MilestoneColumnInstanceID, crdb.ColumnTypeText), + crdb.NewColumn(MilestoneColumnType, crdb.ColumnTypeEnum), + crdb.NewColumn(MilestoneColumnReachedDate, crdb.ColumnTypeTimestamp, crdb.Nullable()), + crdb.NewColumn(MilestoneColumnPushedDate, crdb.ColumnTypeTimestamp, crdb.Nullable()), + crdb.NewColumn(MilestoneColumnPrimaryDomain, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MilestoneColumnIgnoreClientIDs, crdb.ColumnTypeTextArray, crdb.Nullable()), + }, + crdb.NewPrimaryKey(MilestoneColumnInstanceID, MilestoneColumnType), + ), + ) + p.StatementHandler = crdb.NewStatementHandler(ctx, config) + return p +} + +func (p *milestoneProjection) reducers() []handler.AggregateReducer { + return []handler.AggregateReducer{ + { + Aggregate: instance.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: instance.InstanceAddedEventType, + Reduce: p.reduceInstanceAdded, + }, + { + Event: instance.InstanceDomainPrimarySetEventType, + Reduce: p.reduceInstanceDomainPrimarySet, + }, + { + Event: instance.InstanceRemovedEventType, + Reduce: p.reduceInstanceRemoved, + }, + }, + }, + { + Aggregate: project.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: project.ProjectAddedType, + Reduce: p.reduceProjectAdded, + }, + { + Event: project.ApplicationAddedType, + Reduce: p.reduceApplicationAdded, + }, + { + Event: project.OIDCConfigAddedType, + Reduce: p.reduceOIDCConfigAdded, + }, + { + Event: project.APIConfigAddedType, + Reduce: p.reduceAPIConfigAdded, + }, + }, + }, + { + Aggregate: user.AggregateType, + EventRedusers: []handler.EventReducer{ + { + // user.UserTokenAddedType is not emitted on creation of personal access tokens + // PATs have no effect on milestone.AuthenticationSucceededOnApplication or milestone.AuthenticationSucceededOnInstance + Event: user.UserTokenAddedType, + Reduce: p.reduceUserTokenAdded, + }, + }, + }, + { + Aggregate: milestone.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: milestone.PushedEventType, + Reduce: p.reduceMilestonePushed, + }, + }, + }, + } +} + +func (p *milestoneProjection) reduceInstanceAdded(event eventstore.Event) (*handler.Statement, error) { + e, err := assertEvent[*instance.InstanceAddedEvent](event) + if err != nil { + return nil, err + } + allTypes := milestone.AllTypes() + statements := make([]func(eventstore.Event) crdb.Exec, 0, len(allTypes)) + for _, msType := range allTypes { + createColumns := []handler.Column{ + handler.NewCol(MilestoneColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCol(MilestoneColumnType, msType), + } + if msType == milestone.InstanceCreated { + createColumns = append(createColumns, handler.NewCol(MilestoneColumnReachedDate, event.CreationDate())) + } + statements = append(statements, crdb.AddCreateStatement(createColumns)) + } + return crdb.NewMultiStatement(e, statements...), nil +} + +func (p *milestoneProjection) reduceInstanceDomainPrimarySet(event eventstore.Event) (*handler.Statement, error) { + e, err := assertEvent[*instance.DomainPrimarySetEvent](event) + if err != nil { + return nil, err + } + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(MilestoneColumnPrimaryDomain, e.Domain), + }, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, e.Aggregate().InstanceID), + crdb.NewIsNullCond(MilestoneColumnPushedDate), + }, + ), nil +} + +func (p *milestoneProjection) reduceProjectAdded(event eventstore.Event) (*handler.Statement, error) { + if _, err := assertEvent[*project.ProjectAddedEvent](event); err != nil { + return nil, err + } + return p.reduceReachedIfUserEventFunc(milestone.ProjectCreated)(event) +} + +func (p *milestoneProjection) reduceApplicationAdded(event eventstore.Event) (*handler.Statement, error) { + if _, err := assertEvent[*project.ApplicationAddedEvent](event); err != nil { + return nil, err + } + return p.reduceReachedIfUserEventFunc(milestone.ApplicationCreated)(event) +} + +func (p *milestoneProjection) reduceOIDCConfigAdded(event eventstore.Event) (*handler.Statement, error) { + e, err := assertEvent[*project.OIDCConfigAddedEvent](event) + if err != nil { + return nil, err + } + return p.reduceAppConfigAdded(e, e.ClientID) +} + +func (p *milestoneProjection) reduceAPIConfigAdded(event eventstore.Event) (*handler.Statement, error) { + e, err := assertEvent[*project.APIConfigAddedEvent](event) + if err != nil { + return nil, err + } + return p.reduceAppConfigAdded(e, e.ClientID) +} + +func (p *milestoneProjection) reduceUserTokenAdded(event eventstore.Event) (*handler.Statement, error) { + e, err := assertEvent[*user.UserTokenAddedEvent](event) + if err != nil { + return nil, err + } + statements := []func(eventstore.Event) crdb.Exec{ + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(MilestoneColumnReachedDate, event.CreationDate()), + }, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID), + handler.NewCond(MilestoneColumnType, milestone.AuthenticationSucceededOnInstance), + crdb.NewIsNullCond(MilestoneColumnReachedDate), + }, + ), + } + // We ignore authentications without app, for example JWT profile or PAT + if e.ApplicationID != "" { + statements = append(statements, crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(MilestoneColumnReachedDate, event.CreationDate()), + }, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID), + handler.NewCond(MilestoneColumnType, milestone.AuthenticationSucceededOnApplication), + crdb.Not(crdb.NewTextArrayContainsCond(MilestoneColumnIgnoreClientIDs, e.ApplicationID)), + crdb.NewIsNullCond(MilestoneColumnReachedDate), + }, + )) + } + return crdb.NewMultiStatement(e, statements...), nil +} + +func (p *milestoneProjection) reduceInstanceRemoved(event eventstore.Event) (*handler.Statement, error) { + if _, err := assertEvent[*instance.InstanceRemovedEvent](event); err != nil { + return nil, err + } + return p.reduceReachedFunc(milestone.InstanceDeleted)(event) +} + +func (p *milestoneProjection) reduceMilestonePushed(event eventstore.Event) (*handler.Statement, error) { + e, err := assertEvent[*milestone.PushedEvent](event) + if err != nil { + return nil, err + } + if e.MilestoneType != milestone.InstanceDeleted { + return crdb.NewUpdateStatement( + event, + []handler.Column{ + handler.NewCol(MilestoneColumnPushedDate, event.CreationDate()), + }, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID), + handler.NewCond(MilestoneColumnType, e.MilestoneType), + }, + ), nil + } + return crdb.NewDeleteStatement( + event, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID), + }, + ), nil +} + +func (p *milestoneProjection) reduceReachedIfUserEventFunc(msType milestone.Type) func(event eventstore.Event) (*handler.Statement, error) { + return func(event eventstore.Event) (*handler.Statement, error) { + if p.isSystemEvent(event) { + return crdb.NewNoOpStatement(event), nil + } + return p.reduceReachedFunc(msType)(event) + } +} + +func (p *milestoneProjection) reduceReachedFunc(msType milestone.Type) func(event eventstore.Event) (*handler.Statement, error) { + return func(event eventstore.Event) (*handler.Statement, error) { + return crdb.NewUpdateStatement(event, []handler.Column{ + handler.NewCol(MilestoneColumnReachedDate, event.CreationDate()), + }, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID), + handler.NewCond(MilestoneColumnType, msType), + crdb.NewIsNullCond(MilestoneColumnReachedDate), + }), nil + } +} + +func (p *milestoneProjection) reduceAppConfigAdded(event eventstore.Event, clientID string) (*handler.Statement, error) { + if !p.isSystemEvent(event) { + return crdb.NewNoOpStatement(event), nil + } + return crdb.NewUpdateStatement( + event, + []handler.Column{ + crdb.NewArrayAppendCol(MilestoneColumnIgnoreClientIDs, clientID), + }, + []handler.Condition{ + handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID), + handler.NewCond(MilestoneColumnType, milestone.AuthenticationSucceededOnApplication), + crdb.NewIsNullCond(MilestoneColumnReachedDate), + }, + ), nil +} + +func (p *milestoneProjection) isSystemEvent(event eventstore.Event) bool { + if userId, err := strconv.Atoi(event.EditorUser()); err == nil && userId > 0 { + return false + } + lowerEditorService := strings.ToLower(event.EditorService()) + return lowerEditorService == "" || + lowerEditorService == "system" || + lowerEditorService == "system-api" +} diff --git a/internal/query/projection/milestones_test.go b/internal/query/projection/milestones_test.go new file mode 100644 index 000000000..5138fc157 --- /dev/null +++ b/internal/query/projection/milestones_test.go @@ -0,0 +1,404 @@ +package projection + +import ( + "testing" + "time" + + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/handler" + "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/milestone" + "github.com/zitadel/zitadel/internal/repository/project" + "github.com/zitadel/zitadel/internal/repository/user" +) + +func TestMilestonesProjection_reduces(t *testing.T) { + type args struct { + event func(t *testing.T) eventstore.Event + } + now := time.Now() + tests := []struct { + name string + args args + reduce func(event eventstore.Event) (*handler.Statement, error) + want wantReduce + }{ + { + name: "reduceInstanceAdded", + args: args{ + event: getEvent(timedTestEvent( + repository.EventType(instance.InstanceAddedEventType), + instance.AggregateType, + []byte(`{}`), + now, + ), instance.InstanceAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceInstanceAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "INSERT INTO projections.milestones (instance_id, type, reached_date) VALUES ($1, $2, $3)", + expectedArgs: []interface{}{ + "instance-id", + milestone.InstanceCreated, + now, + }, + }, + { + expectedStmt: "INSERT INTO projections.milestones (instance_id, type) VALUES ($1, $2)", + expectedArgs: []interface{}{ + "instance-id", + milestone.AuthenticationSucceededOnInstance, + }, + }, + { + expectedStmt: "INSERT INTO projections.milestones (instance_id, type) VALUES ($1, $2)", + expectedArgs: []interface{}{ + "instance-id", + milestone.ProjectCreated, + }, + }, + { + expectedStmt: "INSERT INTO projections.milestones (instance_id, type) VALUES ($1, $2)", + expectedArgs: []interface{}{ + "instance-id", + milestone.ApplicationCreated, + }, + }, + { + expectedStmt: "INSERT INTO projections.milestones (instance_id, type) VALUES ($1, $2)", + expectedArgs: []interface{}{ + "instance-id", + milestone.AuthenticationSucceededOnApplication, + }, + }, + { + expectedStmt: "INSERT INTO projections.milestones (instance_id, type) VALUES ($1, $2)", + expectedArgs: []interface{}{ + "instance-id", + milestone.InstanceDeleted, + }, + }, + }, + }, + }, + }, + { + name: "reduceInstancePrimaryDomainSet", + args: args{ + event: getEvent(testEvent( + repository.EventType(instance.InstanceDomainPrimarySetEventType), + instance.AggregateType, + []byte(`{"domain": "my.domain"}`), + ), instance.DomainPrimarySetEventMapper), + }, + reduce: (&milestoneProjection{}).reduceInstanceDomainPrimarySet, + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET primary_domain = $1 WHERE (instance_id = $2) AND (last_pushed_date IS NULL)", + expectedArgs: []interface{}{ + "my.domain", + "instance-id", + }, + }, + }, + }, + }, + }, + { + name: "reduceProjectAdded", + args: args{ + event: getEvent(timedTestEvent( + repository.EventType(project.ProjectAddedType), + project.AggregateType, + []byte(`{}`), + now, + ), project.ProjectAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceProjectAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("project"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + now, + "instance-id", + milestone.ProjectCreated, + }, + }, + }, + }, + }, + }, + { + name: "reduceApplicationAdded", + args: args{ + event: getEvent(timedTestEvent( + repository.EventType(project.ApplicationAddedType), + project.AggregateType, + []byte(`{}`), + now, + ), project.ApplicationAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceApplicationAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("project"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + now, + "instance-id", + milestone.ApplicationCreated, + }, + }, + }, + }, + }, + }, + { + name: "reduceOIDCConfigAdded user event", + args: args{ + event: getEvent(testEvent( + repository.EventType(project.OIDCConfigAddedType), + project.AggregateType, + []byte(`{}`), + ), project.OIDCConfigAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceOIDCConfigAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("project"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{}, + }, + }, + { + name: "reduceOIDCConfigAdded system event", + args: args{ + event: getEvent(toSystemEvent(testEvent( + repository.EventType(project.OIDCConfigAddedType), + project.AggregateType, + []byte(`{"clientId": "client-id"}`), + )), project.OIDCConfigAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceOIDCConfigAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("project"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET ignore_client_ids = array_append(ignore_client_ids, $1) WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + "client-id", + "instance-id", + milestone.AuthenticationSucceededOnApplication, + }, + }, + }, + }, + }, + }, + { + name: "reduceAPIConfigAdded user event", + args: args{ + event: getEvent(testEvent( + repository.EventType(project.APIConfigAddedType), + project.AggregateType, + []byte(`{}`), + ), project.APIConfigAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceAPIConfigAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("project"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{}, + }, + }, + { + name: "reduceAPIConfigAdded system event", + args: args{ + event: getEvent(toSystemEvent(testEvent( + repository.EventType(project.APIConfigAddedType), + project.AggregateType, + []byte(`{"clientId": "client-id"}`), + )), project.APIConfigAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceAPIConfigAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("project"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET ignore_client_ids = array_append(ignore_client_ids, $1) WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + "client-id", + "instance-id", + milestone.AuthenticationSucceededOnApplication, + }, + }, + }, + }, + }, + }, + { + name: "reduceUserTokenAdded", + args: args{ + event: getEvent(timedTestEvent( + repository.EventType(user.UserTokenAddedType), + user.AggregateType, + []byte(`{"applicationId": "client-id"}`), + now, + ), user.UserTokenAddedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceUserTokenAdded, + want: wantReduce{ + aggregateType: eventstore.AggregateType("user"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + // TODO: This can be optimized to only use one statement with OR + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + now, + "instance-id", + milestone.AuthenticationSucceededOnInstance, + }, + }, + { + expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (NOT (ignore_client_ids @> $4)) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + now, + "instance-id", + milestone.AuthenticationSucceededOnApplication, + database.StringArray{"client-id"}, + }, + }, + }, + }, + }, + }, + { + name: "reduceInstanceRemoved", + args: args{ + event: getEvent(timedTestEvent( + repository.EventType(instance.InstanceRemovedEventType), + instance.AggregateType, + []byte(`{}`), + now, + ), instance.InstanceRemovedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceInstanceRemoved, + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)", + expectedArgs: []interface{}{ + now, + "instance-id", + milestone.InstanceDeleted, + }, + }, + }, + }, + }, + }, + { + name: "reduceMilestonePushed normal milestone", + args: args{ + event: getEvent(timedTestEvent( + repository.EventType(milestone.PushedEventType), + milestone.AggregateType, + []byte(`{"type": "ProjectCreated"}`), + now, + ), milestone.PushedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceMilestonePushed, + want: wantReduce{ + aggregateType: eventstore.AggregateType("milestone"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.milestones SET last_pushed_date = $1 WHERE (instance_id = $2) AND (type = $3)", + expectedArgs: []interface{}{ + now, + "instance-id", + milestone.ProjectCreated, + }, + }, + }, + }, + }, + }, + { + name: "reduceMilestonePushed instance deleted milestone", + args: args{ + event: getEvent(testEvent( + repository.EventType(milestone.PushedEventType), + milestone.AggregateType, + []byte(`{"type": "InstanceDeleted"}`), + ), milestone.PushedEventMapper), + }, + reduce: (&milestoneProjection{}).reduceMilestonePushed, + want: wantReduce{ + aggregateType: eventstore.AggregateType("milestone"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "DELETE FROM projections.milestones WHERE (instance_id = $1)", + expectedArgs: []interface{}{ + "instance-id", + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + event := baseEvent(t) + got, err := tt.reduce(event) + if !errors.IsErrorInvalidArgument(err) { + t.Errorf("no wrong event mapping: %v, got: %v", err, got) + } + event = tt.args.event(t) + got, err = tt.reduce(event) + assertReduce(t, got, err, MilestonesProjectionTable, tt.want) + }) + } +} diff --git a/internal/query/projection/projection.go b/internal/query/projection/projection.go index 45670b8ba..e8f2bd156 100644 --- a/internal/query/projection/projection.go +++ b/internal/query/projection/projection.go @@ -64,8 +64,11 @@ var ( NotificationPolicyProjection *notificationPolicyProjection NotificationsProjection interface{} NotificationsQuotaProjection interface{} + TelemetryPusherProjection interface{} DeviceAuthProjection *deviceAuthProjection SessionProjection *sessionProjection + AuthRequestProjection *authRequestProjection + MilestoneProjection *milestoneProjection ) type projection interface { @@ -143,6 +146,8 @@ func Create(ctx context.Context, sqlClient *database.DB, es *eventstore.Eventsto NotificationPolicyProjection = newNotificationPolicyProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["notification_policies"])) DeviceAuthProjection = newDeviceAuthProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["device_auth"])) SessionProjection = newSessionProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["sessions"])) + AuthRequestProjection = newAuthRequestProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["auth_requests"])) + MilestoneProjection = newMilestoneProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["milestones"])) newProjectionsList() return nil } @@ -191,7 +196,7 @@ func applyCustomConfig(config crdb.StatementHandlerConfig, customConfig CustomCo // as setup and start currently create them individually, we make sure we get the right one // will be refactored when changing to new id based projections // -// NotificationsProjection is not added here, because it does not statement based / has no proprietary projection table +// Event handlers NotificationsProjection, NotificationsQuotaProjection and NotificationsProjection are not added here, because they do not reduce to database statements func newProjectionsList() { projections = []projection{ OrgProjection, @@ -240,5 +245,7 @@ func newProjectionsList() { NotificationPolicyProjection, DeviceAuthProjection, SessionProjection, + AuthRequestProjection, + MilestoneProjection, } } diff --git a/internal/query/query.go b/internal/query/query.go index 464cf59aa..9355265e1 100644 --- a/internal/query/query.go +++ b/internal/query/query.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "regexp" "sync" "time" @@ -18,9 +19,11 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/query/projection" "github.com/zitadel/zitadel/internal/repository/action" + "github.com/zitadel/zitadel/internal/repository/authrequest" "github.com/zitadel/zitadel/internal/repository/idpintent" iam_repo "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/keypair" + "github.com/zitadel/zitadel/internal/repository/oidcsession" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/session" @@ -88,6 +91,8 @@ func StartQueries( usergrant.RegisterEventMappers(repo.eventstore) session.RegisterEventMappers(repo.eventstore) idpintent.RegisterEventMappers(repo.eventstore) + authrequest.RegisterEventMappers(repo.eventstore) + oidcsession.RegisterEventMappers(repo.eventstore) repo.idpConfigEncryption = idpConfigEncryption repo.multifactors = domain.MultifactorConfigs{ @@ -115,3 +120,19 @@ func (q *Queries) Health(ctx context.Context) error { type prepareDatabase interface { Timetravel(d time.Duration) string } + +// cleanStaticQueries removes whitespaces, +// such as ` `, \t, \n, from queries to improve +// readability in logs and errors. +func cleanStaticQueries(qs ...*string) { + regex := regexp.MustCompile(`\s+`) + for _, q := range qs { + *q = regex.ReplaceAllString(*q, " ") + } +} + +func init() { + cleanStaticQueries( + &authRequestByIDQuery, + ) +} diff --git a/internal/query/query_test.go b/internal/query/query_test.go new file mode 100644 index 000000000..fc16ee9fa --- /dev/null +++ b/internal/query/query_test.go @@ -0,0 +1,17 @@ +package query + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_cleanStaticQueries(t *testing.T) { + query := `select + foo, + bar +from table;` + want := "select foo, bar from table;" + cleanStaticQueries(&query) + assert.Equal(t, want, query) +} diff --git a/internal/query/search_query.go b/internal/query/search_query.go index 0f4314dd0..16d37502d 100644 --- a/internal/query/search_query.go +++ b/internal/query/search_query.go @@ -66,6 +66,27 @@ func (q *NotNullQuery) comp() sq.Sqlizer { return sq.NotEq{q.Column.identifier(): nil} } +type IsNullQuery struct { + Column Column +} + +func NewIsNullQuery(col Column) (*IsNullQuery, error) { + if col.isZero() { + return nil, ErrMissingColumn + } + return &IsNullQuery{ + Column: col, + }, nil +} + +func (q *IsNullQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { + return query.Where(q.comp()) +} + +func (q *IsNullQuery) comp() sq.Sqlizer { + return sq.Eq{q.Column.identifier(): nil} +} + type orQuery struct { queries []SearchQuery } diff --git a/internal/query/session.go b/internal/query/session.go index e9706410a..bcf62ba5d 100644 --- a/internal/query/session.go +++ b/internal/query/session.go @@ -40,6 +40,7 @@ type Session struct { type SessionUserFactor struct { UserID string + ResourceOwner string UserCheckedAt time.Time LoginName string DisplayName string @@ -141,10 +142,14 @@ var ( } ) -func (q *Queries) SessionByID(ctx context.Context, id, sessionToken string) (_ *Session, err error) { +func (q *Queries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string) (_ *Session, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() + if shouldTriggerBulk { + ctx = projection.SessionProjection.Trigger(ctx) + } + query, scan := prepareSessionQuery(ctx, q.client) stmt, args, err := query.Where( sq.Eq{ @@ -221,6 +226,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil SessionColumnUserCheckedAt.identifier(), LoginNameNameCol.identifier(), HumanDisplayNameCol.identifier(), + UserResourceOwnerCol.identifier(), SessionColumnPasswordCheckedAt.identifier(), SessionColumnIntentCheckedAt.identifier(), SessionColumnPasskeyCheckedAt.identifier(), @@ -228,7 +234,8 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil SessionColumnToken.identifier(), ).From(sessionsTable.identifier()). LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)). - LeftJoin(join(HumanUserIDCol, SessionColumnUserID) + db.Timetravel(call.Took(ctx))). + LeftJoin(join(HumanUserIDCol, SessionColumnUserID)). + LeftJoin(join(UserIDCol, SessionColumnUserID) + db.Timetravel(call.Took(ctx))). PlaceholderFormat(sq.Dollar), func(row *sql.Row) (*Session, string, error) { session := new(Session) @@ -237,6 +244,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil userCheckedAt sql.NullTime loginName sql.NullString displayName sql.NullString + userResourceOwner sql.NullString passwordCheckedAt sql.NullTime intentCheckedAt sql.NullTime passkeyCheckedAt sql.NullTime @@ -258,6 +266,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil &userCheckedAt, &loginName, &displayName, + &userResourceOwner, &passwordCheckedAt, &intentCheckedAt, &passkeyCheckedAt, @@ -277,6 +286,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil session.UserFactor.UserCheckedAt = userCheckedAt.Time session.UserFactor.LoginName = loginName.String session.UserFactor.DisplayName = displayName.String + session.UserFactor.ResourceOwner = userResourceOwner.String session.PasswordFactor.PasswordCheckedAt = passwordCheckedAt.Time session.IntentFactor.IntentCheckedAt = intentCheckedAt.Time session.PasskeyFactor.PasskeyCheckedAt = passkeyCheckedAt.Time @@ -300,6 +310,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui SessionColumnUserCheckedAt.identifier(), LoginNameNameCol.identifier(), HumanDisplayNameCol.identifier(), + UserResourceOwnerCol.identifier(), SessionColumnPasswordCheckedAt.identifier(), SessionColumnIntentCheckedAt.identifier(), SessionColumnPasskeyCheckedAt.identifier(), @@ -307,7 +318,8 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui countColumn.identifier(), ).From(sessionsTable.identifier()). LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)). - LeftJoin(join(HumanUserIDCol, SessionColumnUserID) + db.Timetravel(call.Took(ctx))). + LeftJoin(join(HumanUserIDCol, SessionColumnUserID)). + LeftJoin(join(UserIDCol, SessionColumnUserID) + db.Timetravel(call.Took(ctx))). PlaceholderFormat(sq.Dollar), func(rows *sql.Rows) (*Sessions, error) { sessions := &Sessions{Sessions: []*Session{}} @@ -319,6 +331,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui userCheckedAt sql.NullTime loginName sql.NullString displayName sql.NullString + userResourceOwner sql.NullString passwordCheckedAt sql.NullTime intentCheckedAt sql.NullTime passkeyCheckedAt sql.NullTime @@ -339,6 +352,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui &userCheckedAt, &loginName, &displayName, + &userResourceOwner, &passwordCheckedAt, &intentCheckedAt, &passkeyCheckedAt, @@ -354,6 +368,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui session.UserFactor.UserCheckedAt = userCheckedAt.Time session.UserFactor.LoginName = loginName.String session.UserFactor.DisplayName = displayName.String + session.UserFactor.ResourceOwner = userResourceOwner.String session.PasswordFactor.PasswordCheckedAt = passwordCheckedAt.Time session.IntentFactor.IntentCheckedAt = intentCheckedAt.Time session.PasskeyFactor.PasskeyCheckedAt = passkeyCheckedAt.Time diff --git a/internal/query/sessions_test.go b/internal/query/sessions_test.go index 38662ead7..eed2ebafd 100644 --- a/internal/query/sessions_test.go +++ b/internal/query/sessions_test.go @@ -29,6 +29,7 @@ var ( ` projections.sessions3.user_checked_at,` + ` projections.login_names2.login_name,` + ` projections.users8_humans.display_name,` + + ` projections.users8.resource_owner,` + ` projections.sessions3.password_checked_at,` + ` projections.sessions3.intent_checked_at,` + ` projections.sessions3.passkey_checked_at,` + @@ -37,6 +38,7 @@ var ( ` FROM projections.sessions3` + ` LEFT JOIN projections.login_names2 ON projections.sessions3.user_id = projections.login_names2.user_id AND projections.sessions3.instance_id = projections.login_names2.instance_id` + ` LEFT JOIN projections.users8_humans ON projections.sessions3.user_id = projections.users8_humans.user_id AND projections.sessions3.instance_id = projections.users8_humans.instance_id` + + ` LEFT JOIN projections.users8 ON projections.sessions3.user_id = projections.users8.id AND projections.sessions3.instance_id = projections.users8.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions3.id,` + ` projections.sessions3.creation_date,` + @@ -50,6 +52,7 @@ var ( ` projections.sessions3.user_checked_at,` + ` projections.login_names2.login_name,` + ` projections.users8_humans.display_name,` + + ` projections.users8.resource_owner,` + ` projections.sessions3.password_checked_at,` + ` projections.sessions3.intent_checked_at,` + ` projections.sessions3.passkey_checked_at,` + @@ -58,6 +61,7 @@ var ( ` FROM projections.sessions3` + ` LEFT JOIN projections.login_names2 ON projections.sessions3.user_id = projections.login_names2.user_id AND projections.sessions3.instance_id = projections.login_names2.instance_id` + ` LEFT JOIN projections.users8_humans ON projections.sessions3.user_id = projections.users8_humans.user_id AND projections.sessions3.instance_id = projections.users8_humans.instance_id` + + ` LEFT JOIN projections.users8 ON projections.sessions3.user_id = projections.users8.id AND projections.sessions3.instance_id = projections.users8.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) sessionCols = []string{ @@ -73,6 +77,7 @@ var ( "user_checked_at", "login_name", "display_name", + "user_resource_owner", "password_checked_at", "intent_checked_at", "passkey_checked_at", @@ -93,6 +98,7 @@ var ( "user_checked_at", "login_name", "display_name", + "user_resource_owner", "password_checked_at", "intent_checked_at", "passkey_checked_at", @@ -145,6 +151,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, "login-name", "display-name", + "resourceOwner", testNow, testNow, testNow, @@ -172,6 +179,7 @@ func Test_SessionsPrepare(t *testing.T) { UserCheckedAt: testNow, LoginName: "login-name", DisplayName: "display-name", + ResourceOwner: "resourceOwner", }, PasswordFactor: SessionPasswordFactor{ PasswordCheckedAt: testNow, @@ -210,6 +218,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, "login-name", "display-name", + "resourceOwner", testNow, testNow, testNow, @@ -228,6 +237,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, "login-name2", "display-name2", + "resourceOwner", testNow, testNow, testNow, @@ -255,6 +265,7 @@ func Test_SessionsPrepare(t *testing.T) { UserCheckedAt: testNow, LoginName: "login-name", DisplayName: "display-name", + ResourceOwner: "resourceOwner", }, PasswordFactor: SessionPasswordFactor{ PasswordCheckedAt: testNow, @@ -283,6 +294,7 @@ func Test_SessionsPrepare(t *testing.T) { UserCheckedAt: testNow, LoginName: "login-name2", DisplayName: "display-name2", + ResourceOwner: "resourceOwner", }, PasswordFactor: SessionPasswordFactor{ PasswordCheckedAt: testNow, @@ -374,6 +386,7 @@ func Test_SessionPrepare(t *testing.T) { testNow, "login-name", "display-name", + "resourceOwner", testNow, testNow, testNow, @@ -396,6 +409,7 @@ func Test_SessionPrepare(t *testing.T) { UserCheckedAt: testNow, LoginName: "login-name", DisplayName: "display-name", + ResourceOwner: "resourceOwner", }, PasswordFactor: SessionPasswordFactor{ PasswordCheckedAt: testNow, diff --git a/internal/query/user.go b/internal/query/user.go index 1550a4678..46a683e67 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -338,8 +338,8 @@ func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userI defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.UserProjection.Trigger(ctx) - projection.LoginNameProjection.Trigger(ctx) + ctx = projection.UserProjection.Trigger(ctx) + ctx = projection.LoginNameProjection.Trigger(ctx) } query, scan := prepareUserQuery(ctx, q.client) @@ -367,8 +367,8 @@ func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, withOwner defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.UserProjection.Trigger(ctx) - projection.LoginNameProjection.Trigger(ctx) + ctx = projection.UserProjection.Trigger(ctx) + ctx = projection.LoginNameProjection.Trigger(ctx) } query, scan := prepareUserQuery(ctx, q.client) @@ -467,8 +467,8 @@ func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, u defer func() { span.EndWithError(err) }() if shouldTriggered { - projection.UserProjection.Trigger(ctx) - projection.LoginNameProjection.Trigger(ctx) + ctx = projection.UserProjection.Trigger(ctx) + ctx = projection.LoginNameProjection.Trigger(ctx) } query, scan := prepareNotifyUserQuery(ctx, q.client) @@ -496,8 +496,8 @@ func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, withO defer func() { span.EndWithError(err) }() if shouldTriggered { - projection.UserProjection.Trigger(ctx) - projection.LoginNameProjection.Trigger(ctx) + ctx = projection.UserProjection.Trigger(ctx) + ctx = projection.LoginNameProjection.Trigger(ctx) } query, scan := prepareNotifyUserQuery(ctx, q.client) diff --git a/internal/query/user_auth_method.go b/internal/query/user_auth_method.go index dde1a5a38..fc80685bc 100644 --- a/internal/query/user_auth_method.go +++ b/internal/query/user_auth_method.go @@ -79,6 +79,13 @@ var ( name: "count", table: userIDPsCountTable, } + + forceMFATable = loginPolicyTable.setAlias("auth_methods_force_mfa") + forceMFAInstanceID = LoginPolicyColumnInstanceID.setTable(forceMFATable) + forceMFAOrgID = LoginPolicyColumnOrgID.setTable(forceMFATable) + forceMFAIsDefault = LoginPolicyColumnIsDefault.setTable(forceMFATable) + forceMFAForce = LoginPolicyColumnForceMFA.setTable(forceMFATable) + forceMFAForceLocalOnly = LoginPolicyColumnForceMFALocalOnly.setTable(forceMFATable) ) type AuthMethods struct { @@ -170,6 +177,36 @@ func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID stri return userAuthMethodTypes, err } +func (q *Queries) ListUserAuthMethodTypesRequired(ctx context.Context, userID string, withOwnerRemoved bool) (userAuthMethodTypes []domain.UserAuthMethodType, forceMFA, forceMFALocalOnly bool, err error) { + ctxData := authz.GetCtxData(ctx) + if ctxData.UserID != userID { + if err := q.checkPermission(ctx, domain.PermissionUserRead, ctxData.OrgID, userID); err != nil { + return nil, false, false, err + } + } + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + query, scan := prepareUserAuthMethodTypesRequiredQuery(ctx, q.client) + eq := sq.Eq{ + UserIDCol.identifier(): userID, + UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[UserOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() + if err != nil { + return nil, false, false, errors.ThrowInvalidArgument(err, "QUERY-E5ut4", "Errors.Query.InvalidRequest") + } + + rows, err := q.client.QueryContext(ctx, stmt, args...) + if err != nil || rows.Err() != nil { + return nil, false, false, errors.ThrowInternal(err, "QUERY-Dun75", "Errors.Internal") + } + return scan(rows) +} + func NewUserAuthMethodUserIDSearchQuery(value string) (SearchQuery, error) { return NewTextQuery(UserAuthMethodColumnUserID, value, TextEquals) } @@ -311,26 +348,11 @@ func prepareUserAuthMethodsQuery(ctx context.Context, db prepareDatabase) (sq.Se } func prepareActiveUserAuthMethodTypesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) { - authMethodsQuery, authMethodsArgs, err := sq.Select( - "DISTINCT("+authMethodTypeTypes.identifier()+")", - authMethodTypeUserID.identifier(), - authMethodTypeInstanceID.identifier()). - From(authMethodTypeTable.identifier()). - Where(sq.Eq{authMethodTypeState.identifier(): domain.MFAStateReady}). - ToSql() + authMethodsQuery, authMethodsArgs, err := prepareAuthMethodQuery() if err != nil { return sq.SelectBuilder{}, nil } - idpsQuery, _, err := sq.Select( - userIDPsCountUserID.identifier(), - userIDPsCountInstanceID.identifier(), - "COUNT("+userIDPsCountUserID.identifier()+") AS "+userIDPsCountCount.name). - From(userIDPsCountTable.identifier()). - GroupBy( - userIDPsCountUserID.identifier(), - userIDPsCountInstanceID.identifier(), - ). - ToSql() + idpsQuery, err := prepareAuthMethodsIDPsQuery() if err != nil { return sq.SelectBuilder{}, nil } @@ -386,3 +408,110 @@ func prepareActiveUserAuthMethodTypesQuery(ctx context.Context, db prepareDataba }, nil } } + +func prepareUserAuthMethodTypesRequiredQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (_ []domain.UserAuthMethodType, forceMFA, forceMFALocalOnly bool, err error)) { + loginPolicyQuery, err := prepareAuthMethodsForceMFAQuery() + if err != nil { + return sq.SelectBuilder{}, nil + } + authMethodsQuery, authMethodsArgs, err := prepareAuthMethodQuery() + if err != nil { + return sq.SelectBuilder{}, nil + } + idpsQuery, err := prepareAuthMethodsIDPsQuery() + if err != nil { + return sq.SelectBuilder{}, nil + } + return sq.Select( + NotifyPasswordSetCol.identifier(), + authMethodTypeTypes.identifier(), + userIDPsCountCount.identifier(), + forceMFAForce.identifier(), + forceMFAForceLocalOnly.identifier()). + From(userTable.identifier()). + LeftJoin(join(NotifyUserIDCol, UserIDCol)). + LeftJoin("("+authMethodsQuery+") AS "+authMethodTypeTable.alias+" ON "+ + authMethodTypeUserID.identifier()+" = "+UserIDCol.identifier()+" AND "+ + authMethodTypeInstanceID.identifier()+" = "+UserInstanceIDCol.identifier(), + authMethodsArgs...). + LeftJoin("(" + idpsQuery + ") AS " + userIDPsCountTable.alias + " ON " + + userIDPsCountUserID.identifier() + " = " + UserIDCol.identifier() + " AND " + + userIDPsCountInstanceID.identifier() + " = " + UserInstanceIDCol.identifier()). + LeftJoin("(" + loginPolicyQuery + ") AS " + forceMFATable.alias + " ON " + + "(" + forceMFAOrgID.identifier() + " = " + UserInstanceIDCol.identifier() + " OR " + forceMFAOrgID.identifier() + " = " + UserResourceOwnerCol.identifier() + ") AND " + + forceMFAInstanceID.identifier() + " = " + UserInstanceIDCol.identifier() + db.Timetravel(call.Took(ctx))). + PlaceholderFormat(sq.Dollar), + func(rows *sql.Rows) ([]domain.UserAuthMethodType, bool, bool, error) { + userAuthMethodTypes := make([]domain.UserAuthMethodType, 0) + var passwordSet sql.NullBool + var idp sql.NullInt64 + var forceMFA sql.NullBool + var forceMFALocalOnly sql.NullBool + for rows.Next() { + var authMethodType sql.NullInt16 + err := rows.Scan( + &passwordSet, + &authMethodType, + &idp, + &forceMFA, + &forceMFALocalOnly, + ) + if err != nil { + return nil, false, false, err + } + if authMethodType.Valid { + userAuthMethodTypes = append(userAuthMethodTypes, domain.UserAuthMethodType(authMethodType.Int16)) + } + } + if passwordSet.Valid && passwordSet.Bool { + userAuthMethodTypes = append(userAuthMethodTypes, domain.UserAuthMethodTypePassword) + } + if idp.Valid && idp.Int64 > 0 { + logging.Error("IDP", idp.Int64) + userAuthMethodTypes = append(userAuthMethodTypes, domain.UserAuthMethodTypeIDP) + } + + if err := rows.Close(); err != nil { + return nil, false, false, errors.ThrowInternal(err, "QUERY-W4zje", "Errors.Query.CloseRows") + } + + return userAuthMethodTypes, forceMFA.Bool, forceMFALocalOnly.Bool, nil + } +} + +func prepareAuthMethodsIDPsQuery() (string, error) { + idpsQuery, _, err := sq.Select( + userIDPsCountUserID.identifier(), + userIDPsCountInstanceID.identifier(), + "COUNT("+userIDPsCountUserID.identifier()+") AS "+userIDPsCountCount.name). + From(userIDPsCountTable.identifier()). + GroupBy( + userIDPsCountUserID.identifier(), + userIDPsCountInstanceID.identifier(), + ). + ToSql() + return idpsQuery, err +} + +func prepareAuthMethodQuery() (string, []interface{}, error) { + return sq.Select( + "DISTINCT("+authMethodTypeTypes.identifier()+")", + authMethodTypeUserID.identifier(), + authMethodTypeInstanceID.identifier()). + From(authMethodTypeTable.identifier()). + Where(sq.Eq{authMethodTypeState.identifier(): domain.MFAStateReady}). + ToSql() +} + +func prepareAuthMethodsForceMFAQuery() (string, error) { + loginPolicyQuery, _, err := sq.Select( + forceMFAForce.identifier(), + forceMFAForceLocalOnly.identifier(), + forceMFAInstanceID.identifier(), + forceMFAOrgID.identifier(), + ). + From(forceMFATable.identifier()). + OrderBy(forceMFAIsDefault.identifier()). + ToSql() + return loginPolicyQuery, err +} diff --git a/internal/query/user_auth_method_test.go b/internal/query/user_auth_method_test.go index da86a02aa..ec38d04e5 100644 --- a/internal/query/user_auth_method_test.go +++ b/internal/query/user_auth_method_test.go @@ -1,6 +1,7 @@ package query import ( + "context" "database/sql" "database/sql/driver" "errors" @@ -8,6 +9,8 @@ import ( "regexp" "testing" + sq "github.com/Masterminds/squirrel" + "github.com/zitadel/zitadel/internal/domain" ) @@ -53,6 +56,30 @@ var ( "method_type", "idps_count", } + prepareAuthMethodTypesRequiredStmt = `SELECT projections.users8_notifications.password_set,` + + ` auth_method_types.method_type,` + + ` user_idps_count.count,` + + ` auth_methods_force_mfa.force_mfa,` + + ` auth_methods_force_mfa.force_mfa_local_only` + + ` FROM projections.users8` + + ` LEFT JOIN projections.users8_notifications ON projections.users8.id = projections.users8_notifications.user_id AND projections.users8.instance_id = projections.users8_notifications.instance_id` + + ` LEFT JOIN (SELECT DISTINCT(auth_method_types.method_type), auth_method_types.user_id, auth_method_types.instance_id FROM projections.user_auth_methods4 AS auth_method_types` + + ` WHERE auth_method_types.state = $1) AS auth_method_types` + + ` ON auth_method_types.user_id = projections.users8.id AND auth_method_types.instance_id = projections.users8.instance_id` + + ` LEFT JOIN (SELECT user_idps_count.user_id, user_idps_count.instance_id, COUNT(user_idps_count.user_id) AS count FROM projections.idp_user_links3 AS user_idps_count` + + ` GROUP BY user_idps_count.user_id, user_idps_count.instance_id) AS user_idps_count` + + ` ON user_idps_count.user_id = projections.users8.id AND user_idps_count.instance_id = projections.users8.instance_id` + + ` LEFT JOIN (SELECT auth_methods_force_mfa.force_mfa, auth_methods_force_mfa.force_mfa_local_only, auth_methods_force_mfa.instance_id, auth_methods_force_mfa.aggregate_id FROM projections.login_policies5 AS auth_methods_force_mfa ORDER BY auth_methods_force_mfa.is_default) AS auth_methods_force_mfa` + + ` ON (auth_methods_force_mfa.aggregate_id = projections.users8.instance_id OR auth_methods_force_mfa.aggregate_id = projections.users8.resource_owner) AND auth_methods_force_mfa.instance_id = projections.users8.instance_id` + + ` AS OF SYSTEM TIME '-1 ms +` + prepareAuthMethodTypesRequiredCols = []string{ + "password_set", + "method_type", + "idps_count", + "force_mfa", + "force_mfa_local_only", + } ) func Test_UserAuthMethodPrepares(t *testing.T) { @@ -288,6 +315,136 @@ func Test_UserAuthMethodPrepares(t *testing.T) { }, object: nil, }, + { + name: "prepareUserAuthMethodTypesRequiredQuery no result", + prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*testUserAuthMethodTypesRequired, error)) { + builder, scan := prepareUserAuthMethodTypesRequiredQuery(ctx, db) + return builder, func(rows *sql.Rows) (*testUserAuthMethodTypesRequired, error) { + authMethods, forceMFA, forceMFALocalOnly, err := scan(rows) + if err != nil { + return nil, err + } + return &testUserAuthMethodTypesRequired{authMethods: authMethods, forceMFA: forceMFA, forceMFALocalOnly: forceMFALocalOnly}, nil + } + }, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(prepareAuthMethodTypesRequiredStmt), + nil, + nil, + ), + }, + object: &testUserAuthMethodTypesRequired{authMethods: []domain.UserAuthMethodType{}, forceMFA: false}, + }, + { + name: "prepareUserAuthMethodTypesRequiredQuery one second factor", + prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*testUserAuthMethodTypesRequired, error)) { + builder, scan := prepareUserAuthMethodTypesRequiredQuery(ctx, db) + return builder, func(rows *sql.Rows) (*testUserAuthMethodTypesRequired, error) { + authMethods, forceMFA, forceMFALocalOnly, err := scan(rows) + if err != nil { + return nil, err + } + return &testUserAuthMethodTypesRequired{authMethods: authMethods, forceMFA: forceMFA, forceMFALocalOnly: forceMFALocalOnly}, nil + } + }, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(prepareAuthMethodTypesRequiredStmt), + prepareAuthMethodTypesRequiredCols, + [][]driver.Value{ + { + true, + domain.UserAuthMethodTypePasswordless, + 1, + true, + true, + }, + }, + ), + }, + object: &testUserAuthMethodTypesRequired{ + authMethods: []domain.UserAuthMethodType{ + domain.UserAuthMethodTypePasswordless, + domain.UserAuthMethodTypePassword, + domain.UserAuthMethodTypeIDP, + }, + forceMFA: true, + forceMFALocalOnly: true, + }, + }, + { + name: "prepareUserAuthMethodTypesRequiredQuery multiple second factors", + prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*testUserAuthMethodTypesRequired, error)) { + builder, scan := prepareUserAuthMethodTypesRequiredQuery(ctx, db) + return builder, func(rows *sql.Rows) (*testUserAuthMethodTypesRequired, error) { + authMethods, forceMFA, forceMFALocalOnly, err := scan(rows) + if err != nil { + return nil, err + } + return &testUserAuthMethodTypesRequired{authMethods: authMethods, forceMFA: forceMFA, forceMFALocalOnly: forceMFALocalOnly}, nil + } + }, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(prepareAuthMethodTypesRequiredStmt), + prepareAuthMethodTypesRequiredCols, + [][]driver.Value{ + { + true, + domain.UserAuthMethodTypePasswordless, + 1, + true, + true, + }, + { + true, + domain.UserAuthMethodTypeOTP, + 1, + true, + true, + }, + }, + ), + }, + + object: &testUserAuthMethodTypesRequired{ + authMethods: []domain.UserAuthMethodType{ + domain.UserAuthMethodTypePasswordless, + domain.UserAuthMethodTypeOTP, + domain.UserAuthMethodTypePassword, + domain.UserAuthMethodTypeIDP, + }, + forceMFA: true, + forceMFALocalOnly: true, + }, + }, + { + name: "prepareUserAuthMethodTypesRequiredQuery sql err", + prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*testUserAuthMethodTypesRequired, error)) { + builder, scan := prepareUserAuthMethodTypesRequiredQuery(ctx, db) + return builder, func(rows *sql.Rows) (*testUserAuthMethodTypesRequired, error) { + authMethods, forceMFA, forceMFALocalOnly, err := scan(rows) + if err != nil { + return nil, err + } + return &testUserAuthMethodTypesRequired{authMethods: authMethods, forceMFA: forceMFA, forceMFALocalOnly: forceMFALocalOnly}, nil + } + }, + want: want{ + sqlExpectations: mockQueryErr( + regexp.QuoteMeta(prepareAuthMethodTypesRequiredStmt), + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -295,3 +452,10 @@ func Test_UserAuthMethodPrepares(t *testing.T) { }) } } + +// testUserAuthMethodTypesRequired is required as assetPrepare is only able to return a single object from scan +type testUserAuthMethodTypesRequired struct { + authMethods []domain.UserAuthMethodType + forceMFA bool + forceMFALocalOnly bool +} diff --git a/internal/query/user_grant.go b/internal/query/user_grant.go index ceb8652e4..6d0eaa95b 100644 --- a/internal/query/user_grant.go +++ b/internal/query/user_grant.go @@ -8,8 +8,6 @@ import ( sq "github.com/Masterminds/squirrel" - "github.com/zitadel/logging" - "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/call" "github.com/zitadel/zitadel/internal/database" @@ -235,7 +233,7 @@ func (q *Queries) UserGrant(ctx context.Context, shouldTriggerBulk bool, withOwn defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.UserGrantProjection.Trigger(ctx) + ctx = projection.UserGrantProjection.Trigger(ctx) } query, scan := prepareUserGrantQuery(ctx, q.client) @@ -260,9 +258,7 @@ func (q *Queries) UserGrants(ctx context.Context, queries *UserGrantsQueries, sh defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - logging.OnError( - projection.UserGrantProjection.Trigger(ctx), - ).Debug("unable to trigger") + ctx = projection.UserGrantProjection.Trigger(ctx) } query, scan := prepareUserGrantsQuery(ctx, q.client) diff --git a/internal/query/user_metadata.go b/internal/query/user_metadata.go index b7c4c2736..d0a9202b8 100644 --- a/internal/query/user_metadata.go +++ b/internal/query/user_metadata.go @@ -82,7 +82,7 @@ func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bo defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.UserMetadataProjection.Trigger(ctx) + ctx = projection.UserMetadataProjection.Trigger(ctx) } query, scan := prepareUserMetadataQuery(ctx, q.client) @@ -111,7 +111,7 @@ func (q *Queries) SearchUserMetadata(ctx context.Context, shouldTriggerBulk bool defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.UserMetadataProjection.Trigger(ctx) + ctx = projection.UserMetadataProjection.Trigger(ctx) } query, scan := prepareUserMetadataListQuery(ctx, q.client) diff --git a/internal/query/user_password.go b/internal/query/user_password.go index 715c9ed87..97ca99541 100644 --- a/internal/query/user_password.go +++ b/internal/query/user_password.go @@ -15,7 +15,7 @@ import ( type HumanPasswordReadModel struct { *eventstore.ReadModel - Secret *crypto.CryptoValue + EncodedHash string SecretChangeRequired bool Code *crypto.CryptoValue @@ -26,26 +26,21 @@ type HumanPasswordReadModel struct { UserState domain.UserState } -func (q *Queries) GetHumanPassword(ctx context.Context, orgID, userID string) (passwordHash []byte, algorithm string, err error) { +func (q *Queries) GetHumanPassword(ctx context.Context, orgID, userID string) (encodedHash string, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() if userID == "" { - return nil, "", errors.ThrowInvalidArgument(nil, "QUERY-4Mfsf", "Errors.User.UserIDMissing") + return "", errors.ThrowInvalidArgument(nil, "QUERY-4Mfsf", "Errors.User.UserIDMissing") } existingPassword, err := q.passwordReadModel(ctx, userID, orgID) if err != nil { - return nil, "", errors.ThrowInternal(nil, "QUERY-p1k1n2i", "Errors.User.NotFound") + return "", errors.ThrowInternal(nil, "QUERY-p1k1n2i", "Errors.User.NotFound") } if existingPassword.UserState == domain.UserStateUnspecified || existingPassword.UserState == domain.UserStateDeleted { - return nil, "", errors.ThrowPreconditionFailed(nil, "QUERY-3n77z", "Errors.User.NotFound") + return "", errors.ThrowPreconditionFailed(nil, "QUERY-3n77z", "Errors.User.NotFound") } - - if existingPassword.Secret != nil && existingPassword.Secret.Crypted != nil { - return existingPassword.Secret.Crypted, existingPassword.Secret.Algorithm, nil - } - - return nil, "", nil + return existingPassword.EncodedHash, nil } func (q *Queries) passwordReadModel(ctx context.Context, userID, resourceOwner string) (readModel *HumanPasswordReadModel, err error) { @@ -77,11 +72,11 @@ func (wm *HumanPasswordReadModel) Reduce() error { for _, event := range wm.Events { switch e := event.(type) { case *user.HumanAddedEvent: - wm.Secret = e.Secret + wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash) wm.SecretChangeRequired = e.ChangeRequired wm.UserState = domain.UserStateActive case *user.HumanRegisteredEvent: - wm.Secret = e.Secret + wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash) wm.SecretChangeRequired = e.ChangeRequired wm.UserState = domain.UserStateActive case *user.HumanInitialCodeAddedEvent: @@ -89,7 +84,7 @@ func (wm *HumanPasswordReadModel) Reduce() error { case *user.HumanInitializedCheckSucceededEvent: wm.UserState = domain.UserStateActive case *user.HumanPasswordChangedEvent: - wm.Secret = e.Secret + wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash) wm.SecretChangeRequired = e.ChangeRequired wm.Code = nil wm.PasswordCheckFailedCount = 0 @@ -109,6 +104,8 @@ func (wm *HumanPasswordReadModel) Reduce() error { wm.PasswordCheckFailedCount = 0 case *user.UserRemovedEvent: wm.UserState = domain.UserStateDeleted + case *user.HumanPasswordHashUpdatedEvent: + wm.EncodedHash = e.EncodedHash } } return wm.ReadModel.Reduce() @@ -139,7 +136,8 @@ func (wm *HumanPasswordReadModel) Query() *eventstore.SearchQueryBuilder { user.UserV1PasswordCodeAddedType, user.UserV1EmailVerifiedType, user.UserV1PasswordCheckFailedType, - user.UserV1PasswordCheckSucceededType). + user.UserV1PasswordCheckSucceededType, + user.UserV1PasswordHashUpdatedType). Builder() if wm.ResourceOwner != "" { diff --git a/internal/query/user_personal_access_token.go b/internal/query/user_personal_access_token.go index 4afab7ec8..5558eed3c 100644 --- a/internal/query/user_personal_access_token.go +++ b/internal/query/user_personal_access_token.go @@ -90,7 +90,7 @@ func (q *Queries) PersonalAccessTokenByID(ctx context.Context, shouldTriggerBulk defer func() { span.EndWithError(err) }() if shouldTriggerBulk { - projection.PersonalAccessTokenProjection.Trigger(ctx) + ctx = projection.PersonalAccessTokenProjection.Trigger(ctx) } query, scan := preparePersonalAccessTokenQuery(ctx, q.client) diff --git a/internal/repository/authrequest/aggregate.go b/internal/repository/authrequest/aggregate.go new file mode 100644 index 000000000..ce6d8adc2 --- /dev/null +++ b/internal/repository/authrequest/aggregate.go @@ -0,0 +1,26 @@ +package authrequest + +import ( + "github.com/zitadel/zitadel/internal/eventstore" +) + +const ( + AggregateType = "auth_request" + AggregateVersion = "v1" +) + +type Aggregate struct { + eventstore.Aggregate +} + +func NewAggregate(id, instanceID string) *Aggregate { + return &Aggregate{ + Aggregate: eventstore.Aggregate{ + Type: AggregateType, + Version: AggregateVersion, + ID: id, + ResourceOwner: instanceID, + InstanceID: instanceID, + }, + } +} diff --git a/internal/repository/authrequest/auth_request.go b/internal/repository/authrequest/auth_request.go new file mode 100644 index 000000000..a279f23c9 --- /dev/null +++ b/internal/repository/authrequest/auth_request.go @@ -0,0 +1,287 @@ +package authrequest + +import ( + "context" + "encoding/json" + "time" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/repository" +) + +const ( + authRequestEventPrefix = "auth_request." + AddedType = authRequestEventPrefix + "added" + FailedType = authRequestEventPrefix + "failed" + CodeAddedType = authRequestEventPrefix + "code.added" + SessionLinkedType = authRequestEventPrefix + "session.linked" + CodeExchangedType = authRequestEventPrefix + "code.exchanged" + SucceededType = authRequestEventPrefix + "succeeded" +) + +type AddedEvent struct { + eventstore.BaseEvent `json:"-"` + + LoginClient string `json:"login_client"` + ClientID string `json:"client_id"` + RedirectURI string `json:"redirect_uri"` + State string `json:"state,omitempty"` + Nonce string `json:"nonce,omitempty"` + Scope []string `json:"scope,omitempty"` + Audience []string `json:"audience,omitempty"` + ResponseType domain.OIDCResponseType `json:"response_type,omitempty"` + CodeChallenge *domain.OIDCCodeChallenge `json:"code_challenge,omitempty"` + Prompt []domain.Prompt `json:"prompt,omitempty"` + UILocales []string `json:"ui_locales,omitempty"` + MaxAge *time.Duration `json:"max_age,omitempty"` + LoginHint *string `json:"login_hint,omitempty"` + HintUserID *string `json:"hint_user_id,omitempty"` +} + +func (e *AddedEvent) Data() interface{} { + return e +} + +func (e *AddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewAddedEvent(ctx context.Context, + aggregate *eventstore.Aggregate, + loginClient, + clientID, + redirectURI, + state, + nonce string, + scope, + audience []string, + responseType domain.OIDCResponseType, + codeChallenge *domain.OIDCCodeChallenge, + prompt []domain.Prompt, + uiLocales []string, + maxAge *time.Duration, + loginHint, + hintUserID *string, +) *AddedEvent { + return &AddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + AddedType, + ), + LoginClient: loginClient, + ClientID: clientID, + RedirectURI: redirectURI, + State: state, + Nonce: nonce, + Scope: scope, + Audience: audience, + ResponseType: responseType, + CodeChallenge: codeChallenge, + Prompt: prompt, + UILocales: uiLocales, + MaxAge: maxAge, + LoginHint: loginHint, + HintUserID: hintUserID, + } +} + +func AddedEventMapper(event *repository.Event) (eventstore.Event, error) { + added := &AddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, added) + if err != nil { + return nil, errors.ThrowInternal(err, "AUTHR-DG4gn", "unable to unmarshal auth request added") + } + + return added, nil +} + +type SessionLinkedEvent struct { + eventstore.BaseEvent `json:"-"` + + SessionID string `json:"session_id"` + UserID string `json:"user_id"` + AuthTime time.Time `json:"auth_time"` + AuthMethods []domain.UserAuthMethodType `json:"auth_methods"` +} + +func (e *SessionLinkedEvent) Data() interface{} { + return e +} + +func (e *SessionLinkedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewSessionLinkedEvent(ctx context.Context, + aggregate *eventstore.Aggregate, + sessionID, + userID string, + authTime time.Time, + authMethods []domain.UserAuthMethodType, +) *SessionLinkedEvent { + return &SessionLinkedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + SessionLinkedType, + ), + SessionID: sessionID, + UserID: userID, + AuthTime: authTime, + AuthMethods: authMethods, + } +} + +func SessionLinkedEventMapper(event *repository.Event) (eventstore.Event, error) { + added := &SessionLinkedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, added) + if err != nil { + return nil, errors.ThrowInternal(err, "AUTHR-Sfe3w", "unable to unmarshal auth request session linked") + } + + return added, nil +} + +type FailedEvent struct { + eventstore.BaseEvent `json:"-"` + + Reason domain.OIDCErrorReason `json:"reason,omitempty"` +} + +func (e *FailedEvent) Data() interface{} { + return e +} + +func (e *FailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewFailedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + reason domain.OIDCErrorReason, +) *FailedEvent { + return &FailedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + FailedType, + ), + Reason: reason, + } +} + +func FailedEventMapper(event *repository.Event) (eventstore.Event, error) { + added := &FailedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, added) + if err != nil { + return nil, errors.ThrowInternal(err, "AUTHR-Sfe3w", "unable to unmarshal auth request session linked") + } + + return added, nil +} + +type CodeAddedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *CodeAddedEvent) Data() interface{} { + return e +} + +func (e *CodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewCodeAddedEvent(ctx context.Context, + aggregate *eventstore.Aggregate, +) *CodeAddedEvent { + return &CodeAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + CodeAddedType, + ), + } +} + +func CodeAddedEventMapper(event *repository.Event) (eventstore.Event, error) { + added := &CodeAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, added) + if err != nil { + return nil, errors.ThrowInternal(err, "AUTHR-Sfe3w", "unable to unmarshal auth request code added") + } + + return added, nil +} + +type CodeExchangedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *CodeExchangedEvent) Data() interface{} { + return nil +} + +func (e *CodeExchangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewCodeExchangedEvent(ctx context.Context, + aggregate *eventstore.Aggregate, +) *CodeExchangedEvent { + return &CodeExchangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + CodeExchangedType, + ), + } +} + +func CodeExchangedEventMapper(event *repository.Event) (eventstore.Event, error) { + return &CodeExchangedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + }, nil +} + +type SucceededEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *SucceededEvent) Data() interface{} { + return nil +} + +func (e *SucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewSucceededEvent(ctx context.Context, + aggregate *eventstore.Aggregate, +) *SucceededEvent { + return &SucceededEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + SucceededType, + ), + } +} + +func SucceededEventMapper(event *repository.Event) (eventstore.Event, error) { + return &SucceededEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + }, nil +} diff --git a/internal/repository/authrequest/eventstore.go b/internal/repository/authrequest/eventstore.go new file mode 100644 index 000000000..c1bfed7dc --- /dev/null +++ b/internal/repository/authrequest/eventstore.go @@ -0,0 +1,12 @@ +package authrequest + +import "github.com/zitadel/zitadel/internal/eventstore" + +func RegisterEventMappers(es *eventstore.Eventstore) { + es.RegisterFilterEventMapper(AggregateType, AddedType, AddedEventMapper). + RegisterFilterEventMapper(AggregateType, SessionLinkedType, SessionLinkedEventMapper). + RegisterFilterEventMapper(AggregateType, CodeAddedType, CodeAddedEventMapper). + RegisterFilterEventMapper(AggregateType, CodeExchangedType, CodeExchangedEventMapper). + RegisterFilterEventMapper(AggregateType, FailedType, FailedEventMapper). + RegisterFilterEventMapper(AggregateType, SucceededType, SucceededEventMapper) +} diff --git a/internal/repository/instance/policy_login.go b/internal/repository/instance/policy_login.go index fad06fa71..73a0b3ef4 100644 --- a/internal/repository/instance/policy_login.go +++ b/internal/repository/instance/policy_login.go @@ -27,6 +27,7 @@ func NewLoginPolicyAddedEvent( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, @@ -50,6 +51,7 @@ func NewLoginPolicyAddedEvent( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, diff --git a/internal/repository/milestone/aggregate.go b/internal/repository/milestone/aggregate.go new file mode 100644 index 000000000..bb9ca99cb --- /dev/null +++ b/internal/repository/milestone/aggregate.go @@ -0,0 +1,30 @@ +package milestone + +import ( + "context" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/eventstore" +) + +const ( + AggregateType = "milestone" + AggregateVersion = "v1" +) + +type Aggregate struct { + eventstore.Aggregate +} + +func NewAggregate(ctx context.Context, id string) *Aggregate { + instanceID := authz.GetInstance(ctx).InstanceID() + return &Aggregate{ + Aggregate: eventstore.Aggregate{ + Type: AggregateType, + Version: AggregateVersion, + ID: id, + ResourceOwner: instanceID, + InstanceID: instanceID, + }, + } +} diff --git a/internal/repository/milestone/events.go b/internal/repository/milestone/events.go new file mode 100644 index 000000000..5ec2f96f9 --- /dev/null +++ b/internal/repository/milestone/events.go @@ -0,0 +1,54 @@ +package milestone + +import ( + "context" + + "github.com/zitadel/zitadel/internal/eventstore" +) + +const ( + eventTypePrefix = eventstore.EventType("milestone.") + PushedEventType = eventTypePrefix + "pushed" +) + +type PushedEvent struct { + *eventstore.BaseEvent `json:"-"` + MilestoneType Type `json:"type"` + ExternalDomain string `json:"externalDomain"` + PrimaryDomain string `json:"primaryDomain"` + Endpoints []string `json:"endpoints"` +} + +func (p *PushedEvent) Data() interface{} { + return p +} + +func (p *PushedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (p *PushedEvent) SetBaseEvent(b *eventstore.BaseEvent) { + p.BaseEvent = b +} + +var PushedEventMapper = eventstore.GenericEventMapper[PushedEvent] + +func NewPushedEvent( + ctx context.Context, + aggregate *Aggregate, + msType Type, + endpoints []string, + externalDomain, primaryDomain string, +) *PushedEvent { + return &PushedEvent{ + BaseEvent: eventstore.NewBaseEventForPush( + ctx, + &aggregate.Aggregate, + PushedEventType, + ), + MilestoneType: msType, + Endpoints: endpoints, + ExternalDomain: externalDomain, + PrimaryDomain: primaryDomain, + } +} diff --git a/internal/repository/milestone/eventstore.go b/internal/repository/milestone/eventstore.go new file mode 100644 index 000000000..4f82b0819 --- /dev/null +++ b/internal/repository/milestone/eventstore.go @@ -0,0 +1,9 @@ +package milestone + +import ( + "github.com/zitadel/zitadel/internal/eventstore" +) + +func RegisterEventMappers(es *eventstore.Eventstore) { + es.RegisterFilterEventMapper(AggregateType, PushedEventType, PushedEventMapper) +} diff --git a/internal/repository/milestone/type.go b/internal/repository/milestone/type.go new file mode 100644 index 000000000..f57bb032e --- /dev/null +++ b/internal/repository/milestone/type.go @@ -0,0 +1,59 @@ +//go:generate stringer -type Type + +package milestone + +import ( + "fmt" + "strings" +) + +type Type int + +const ( + unknown Type = iota + + InstanceCreated + AuthenticationSucceededOnInstance + ProjectCreated + ApplicationCreated + AuthenticationSucceededOnApplication + InstanceDeleted + + typesCount +) + +func AllTypes() []Type { + types := make([]Type, typesCount-1) + for i := Type(1); i < typesCount; i++ { + types[i-1] = i + } + return types +} + +func (t *Type) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, t.String())), nil +} + +func (t *Type) UnmarshalJSON(data []byte) error { + *t = typeFromString(strings.Trim(string(data), `"`)) + return nil +} + +func typeFromString(t string) Type { + switch t { + case InstanceCreated.String(): + return InstanceCreated + case AuthenticationSucceededOnInstance.String(): + return AuthenticationSucceededOnInstance + case ProjectCreated.String(): + return ProjectCreated + case ApplicationCreated.String(): + return ApplicationCreated + case AuthenticationSucceededOnApplication.String(): + return AuthenticationSucceededOnApplication + case InstanceDeleted.String(): + return InstanceDeleted + default: + return unknown + } +} diff --git a/internal/repository/milestone/type_string.go b/internal/repository/milestone/type_string.go new file mode 100644 index 000000000..ce6a98441 --- /dev/null +++ b/internal/repository/milestone/type_string.go @@ -0,0 +1,30 @@ +// Code generated by "stringer -type Type"; DO NOT EDIT. + +package milestone + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[unknown-0] + _ = x[InstanceCreated-1] + _ = x[AuthenticationSucceededOnInstance-2] + _ = x[ProjectCreated-3] + _ = x[ApplicationCreated-4] + _ = x[AuthenticationSucceededOnApplication-5] + _ = x[InstanceDeleted-6] + _ = x[typesCount-7] +} + +const _Type_name = "unknownInstanceCreatedAuthenticationSucceededOnInstanceProjectCreatedApplicationCreatedAuthenticationSucceededOnApplicationInstanceDeletedtypesCount" + +var _Type_index = [...]uint8{0, 7, 22, 55, 69, 87, 123, 138, 148} + +func (i Type) String() string { + if i < 0 || i >= Type(len(_Type_index)-1) { + return "Type(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Type_name[_Type_index[i]:_Type_index[i+1]] +} diff --git a/internal/repository/oidcsession/aggregate.go b/internal/repository/oidcsession/aggregate.go new file mode 100644 index 000000000..920f6c9fc --- /dev/null +++ b/internal/repository/oidcsession/aggregate.go @@ -0,0 +1,25 @@ +package oidcsession + +import ( + "github.com/zitadel/zitadel/internal/eventstore" +) + +const ( + AggregateType = "oidc_session" + AggregateVersion = "v1" +) + +type Aggregate struct { + eventstore.Aggregate +} + +func NewAggregate(id, resourceOwner string) *Aggregate { + return &Aggregate{ + Aggregate: eventstore.Aggregate{ + Type: AggregateType, + Version: AggregateVersion, + ID: id, + ResourceOwner: resourceOwner, + }, + } +} diff --git a/internal/repository/oidcsession/eventstore.go b/internal/repository/oidcsession/eventstore.go new file mode 100644 index 000000000..091bcf5d4 --- /dev/null +++ b/internal/repository/oidcsession/eventstore.go @@ -0,0 +1,15 @@ +package oidcsession + +import ( + "github.com/zitadel/zitadel/internal/eventstore" +) + +func RegisterEventMappers(es *eventstore.Eventstore) { + es.RegisterFilterEventMapper(AggregateType, AddedType, eventstore.GenericEventMapper[AddedEvent]). + RegisterFilterEventMapper(AggregateType, AccessTokenAddedType, eventstore.GenericEventMapper[AccessTokenAddedEvent]). + RegisterFilterEventMapper(AggregateType, AccessTokenRevokedType, eventstore.GenericEventMapper[AccessTokenRevokedEvent]). + RegisterFilterEventMapper(AggregateType, RefreshTokenAddedType, eventstore.GenericEventMapper[RefreshTokenAddedEvent]). + RegisterFilterEventMapper(AggregateType, RefreshTokenRenewedType, eventstore.GenericEventMapper[RefreshTokenRenewedEvent]). + RegisterFilterEventMapper(AggregateType, RefreshTokenRevokedType, eventstore.GenericEventMapper[RefreshTokenRevokedEvent]) + +} diff --git a/internal/repository/oidcsession/oidc_session.go b/internal/repository/oidcsession/oidc_session.go new file mode 100644 index 000000000..8887b6192 --- /dev/null +++ b/internal/repository/oidcsession/oidc_session.go @@ -0,0 +1,241 @@ +package oidcsession + +import ( + "context" + "time" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/eventstore" +) + +const ( + oidcSessionEventPrefix = "oidc_session." + AddedType = oidcSessionEventPrefix + "added" + AccessTokenAddedType = oidcSessionEventPrefix + "access_token.added" + AccessTokenRevokedType = oidcSessionEventPrefix + "access_token.revoked" + RefreshTokenAddedType = oidcSessionEventPrefix + "refresh_token.added" + RefreshTokenRenewedType = oidcSessionEventPrefix + "refresh_token.renewed" + RefreshTokenRevokedType = oidcSessionEventPrefix + "refresh_token.revoked" +) + +type AddedEvent struct { + eventstore.BaseEvent `json:"-"` + + UserID string `json:"userID"` + SessionID string `json:"sessionID"` + ClientID string `json:"clientID"` + Audience []string `json:"audience"` + Scope []string `json:"scope"` + AuthMethods []domain.UserAuthMethodType `json:"authMethods"` + AuthTime time.Time `json:"authTime"` +} + +func (e *AddedEvent) Data() interface{} { + return e +} + +func (e *AddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *AddedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewAddedEvent(ctx context.Context, + aggregate *eventstore.Aggregate, + userID, + sessionID, + clientID string, + audience, + scope []string, + authMethods []domain.UserAuthMethodType, + authTime time.Time, +) *AddedEvent { + return &AddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + AddedType, + ), + UserID: userID, + SessionID: sessionID, + ClientID: clientID, + Audience: audience, + Scope: scope, + AuthMethods: authMethods, + AuthTime: authTime, + } +} + +type AccessTokenAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + ID string `json:"id"` + Scope []string `json:"scope"` + Lifetime time.Duration `json:"lifetime"` +} + +func (e *AccessTokenAddedEvent) Data() interface{} { + return e +} + +func (e *AccessTokenAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *AccessTokenAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewAccessTokenAddedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + id string, + scope []string, + lifetime time.Duration, +) *AccessTokenAddedEvent { + return &AccessTokenAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + AccessTokenAddedType, + ), + ID: id, + Scope: scope, + Lifetime: lifetime, + } +} + +type AccessTokenRevokedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *AccessTokenRevokedEvent) Data() interface{} { + return e +} + +func (e *AccessTokenRevokedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *AccessTokenRevokedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewAccessTokenRevokedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, +) *AccessTokenAddedEvent { + return &AccessTokenAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + AccessTokenRevokedType, + ), + } +} + +type RefreshTokenAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + ID string `json:"id"` + Lifetime time.Duration `json:"lifetime"` + IdleLifetime time.Duration `json:"idleLifetime"` +} + +func (e *RefreshTokenAddedEvent) Data() interface{} { + return e +} + +func (e *RefreshTokenAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *RefreshTokenAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewRefreshTokenAddedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + id string, + lifetime, + idleLifetime time.Duration, +) *RefreshTokenAddedEvent { + return &RefreshTokenAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + RefreshTokenAddedType, + ), + ID: id, + Lifetime: lifetime, + IdleLifetime: idleLifetime, + } +} + +type RefreshTokenRenewedEvent struct { + eventstore.BaseEvent `json:"-"` + + ID string `json:"id"` + IdleLifetime time.Duration `json:"idleLifetime"` +} + +func (e *RefreshTokenRenewedEvent) Data() interface{} { + return e +} + +func (e *RefreshTokenRenewedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *RefreshTokenRenewedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewRefreshTokenRenewedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + id string, + idleLifetime time.Duration, +) *RefreshTokenRenewedEvent { + return &RefreshTokenRenewedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + RefreshTokenRenewedType, + ), + ID: id, + IdleLifetime: idleLifetime, + } +} + +type RefreshTokenRevokedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *RefreshTokenRevokedEvent) Data() interface{} { + return e +} + +func (e *RefreshTokenRevokedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *RefreshTokenRevokedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewRefreshTokenRevokedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, +) *RefreshTokenRevokedEvent { + return &RefreshTokenRevokedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + RefreshTokenRevokedType, + ), + } +} diff --git a/internal/repository/org/policy_login.go b/internal/repository/org/policy_login.go index 449e3e10a..95e38ca92 100644 --- a/internal/repository/org/policy_login.go +++ b/internal/repository/org/policy_login.go @@ -28,6 +28,7 @@ func NewLoginPolicyAddedEvent( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, @@ -51,6 +52,7 @@ func NewLoginPolicyAddedEvent( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, diff --git a/internal/repository/policy/login.go b/internal/repository/policy/login.go index dfd2d0afd..790b1a571 100644 --- a/internal/repository/policy/login.go +++ b/internal/repository/policy/login.go @@ -24,6 +24,7 @@ type LoginPolicyAddedEvent struct { AllowRegister bool `json:"allowRegister,omitempty"` AllowExternalIDP bool `json:"allowExternalIdp,omitempty"` ForceMFA bool `json:"forceMFA,omitempty"` + ForceMFALocalOnly bool `json:"forceMFALocalOnly,omitempty"` HidePasswordReset bool `json:"hidePasswordReset,omitempty"` IgnoreUnknownUsernames bool `json:"ignoreUnknownUsernames,omitempty"` AllowDomainDiscovery bool `json:"allowDomainDiscovery,omitempty"` @@ -52,6 +53,7 @@ func NewLoginPolicyAddedEvent( allowRegister, allowExternalIDP, forceMFA, + forceMFALocalOnly, hidePasswordReset, ignoreUnknownUsernames, allowDomainDiscovery, @@ -71,6 +73,7 @@ func NewLoginPolicyAddedEvent( AllowRegister: allowRegister, AllowUserNamePassword: allowUserNamePassword, ForceMFA: forceMFA, + ForceMFALocalOnly: forceMFALocalOnly, PasswordlessType: passwordlessType, HidePasswordReset: hidePasswordReset, IgnoreUnknownUsernames: ignoreUnknownUsernames, @@ -106,6 +109,7 @@ type LoginPolicyChangedEvent struct { AllowRegister *bool `json:"allowRegister,omitempty"` AllowExternalIDP *bool `json:"allowExternalIdp,omitempty"` ForceMFA *bool `json:"forceMFA,omitempty"` + ForceMFALocalOnly *bool `json:"forceMFALocalOnly,omitempty"` HidePasswordReset *bool `json:"hidePasswordReset,omitempty"` IgnoreUnknownUsernames *bool `json:"ignoreUnknownUsernames,omitempty"` AllowDomainDiscovery *bool `json:"allowDomainDiscovery,omitempty"` @@ -170,6 +174,12 @@ func ChangeForceMFA(forceMFA bool) func(*LoginPolicyChangedEvent) { } } +func ChangeForceMFALocalOnly(forceMFALocalOnly bool) func(*LoginPolicyChangedEvent) { + return func(e *LoginPolicyChangedEvent) { + e.ForceMFALocalOnly = &forceMFALocalOnly + } +} + func ChangePasswordlessType(passwordlessType domain.PasswordlessType) func(*LoginPolicyChangedEvent) { return func(e *LoginPolicyChangedEvent) { e.PasswordlessType = &passwordlessType diff --git a/internal/repository/pseudo/aggregate.go b/internal/repository/pseudo/aggregate.go new file mode 100644 index 000000000..811f56661 --- /dev/null +++ b/internal/repository/pseudo/aggregate.go @@ -0,0 +1,21 @@ +package pseudo + +import "github.com/zitadel/zitadel/internal/eventstore" + +const ( + AggregateType = "pseudo" + AggregateVersion = "v1" +) + +type Aggregate struct { + eventstore.Aggregate +} + +func NewAggregate() *Aggregate { + return &Aggregate{ + Aggregate: eventstore.Aggregate{ + Type: AggregateType, + Version: AggregateVersion, + }, + } +} diff --git a/internal/repository/pseudo/events.go b/internal/repository/pseudo/events.go new file mode 100644 index 000000000..0baaa9368 --- /dev/null +++ b/internal/repository/pseudo/events.go @@ -0,0 +1,40 @@ +// Package pseudo contains virtual events, that are not stored in the eventstore. +package pseudo + +import ( + "context" + "time" + + "github.com/zitadel/zitadel/internal/eventstore" +) + +const ( + eventTypePrefix = eventstore.EventType("pseudo.") + ScheduledEventType = eventTypePrefix + "timestamp" +) + +var _ eventstore.Event = (*ScheduledEvent)(nil) + +type ScheduledEvent struct { + *eventstore.BaseEvent `json:"-"` + Timestamp time.Time `json:"-"` + InstanceIDs []string `json:"-"` +} + +// NewScheduledEvent returns an event that can be processed by event handlers like any other event. +// It receives the current timestamp and an ID list of instances that are active and should be processed. +func NewScheduledEvent( + ctx context.Context, + timestamp time.Time, + instanceIDs ...string, +) *ScheduledEvent { + return &ScheduledEvent{ + BaseEvent: eventstore.NewBaseEventForPush( + ctx, + &NewAggregate().Aggregate, + ScheduledEventType, + ), + Timestamp: timestamp, + InstanceIDs: instanceIDs, + } +} diff --git a/internal/repository/user/eventstore.go b/internal/repository/user/eventstore.go index d216c910c..847736b60 100644 --- a/internal/repository/user/eventstore.go +++ b/internal/repository/user/eventstore.go @@ -17,6 +17,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(AggregateType, UserV1PasswordCodeSentType, HumanPasswordCodeSentEventMapper). RegisterFilterEventMapper(AggregateType, UserV1PasswordCheckSucceededType, HumanPasswordCheckSucceededEventMapper). RegisterFilterEventMapper(AggregateType, UserV1PasswordCheckFailedType, HumanPasswordCheckFailedEventMapper). + RegisterFilterEventMapper(AggregateType, UserV1PasswordHashUpdatedType, eventstore.GenericEventMapper[HumanPasswordHashUpdatedEvent]). RegisterFilterEventMapper(AggregateType, UserV1EmailChangedType, HumanEmailChangedEventMapper). RegisterFilterEventMapper(AggregateType, UserV1EmailVerifiedType, HumanEmailVerifiedEventMapper). RegisterFilterEventMapper(AggregateType, UserV1EmailVerificationFailedType, HumanEmailVerificationFailedEventMapper). diff --git a/internal/repository/user/human.go b/internal/repository/user/human.go index 6184b7d07..075fd55ca 100644 --- a/internal/repository/user/human.go +++ b/internal/repository/user/human.go @@ -48,7 +48,10 @@ type HumanAddedEvent struct { Region string `json:"region,omitempty"` StreetAddress string `json:"streetAddress,omitempty"` + // New events only use EncodedHash. However, the secret field + // is preserved to handle events older than the switch to Passwap. Secret *crypto.CryptoValue `json:"secret,omitempty"` + EncodedHash string `json:"encodedHash,omitempty"` ChangeRequired bool `json:"changeRequired,omitempty"` } @@ -81,10 +84,10 @@ func (e *HumanAddedEvent) AddPhoneData( } func (e *HumanAddedEvent) AddPasswordData( - secret *crypto.CryptoValue, + encoded string, changeRequired bool, ) { - e.Secret = secret + e.EncodedHash = encoded e.ChangeRequired = changeRequired } @@ -149,8 +152,12 @@ type HumanRegisteredEvent struct { PostalCode string `json:"postalCode,omitempty"` Region string `json:"region,omitempty"` StreetAddress string `json:"streetAddress,omitempty"` - Secret *crypto.CryptoValue `json:"secret,omitempty"` - ChangeRequired bool `json:"changeRequired,omitempty"` + + // New events only use EncodedHash. However, the secret field + // is preserved to handle events older than the switch to Passwap. + Secret *crypto.CryptoValue `json:"secret,omitempty"` // legacy + EncodedHash string `json:"encodedHash,omitempty"` + ChangeRequired bool `json:"changeRequired,omitempty"` } func (e *HumanRegisteredEvent) Data() interface{} { @@ -182,10 +189,10 @@ func (e *HumanRegisteredEvent) AddPhoneData( } func (e *HumanRegisteredEvent) AddPasswordData( - secret *crypto.CryptoValue, + encoded string, changeRequired bool, ) { - e.Secret = secret + e.EncodedHash = encoded e.ChangeRequired = changeRequired } diff --git a/internal/repository/user/human_password.go b/internal/repository/user/human_password.go index ccd38527d..f2f40cd6c 100644 --- a/internal/repository/user/human_password.go +++ b/internal/repository/user/human_password.go @@ -26,7 +26,10 @@ const ( type HumanPasswordChangedEvent struct { eventstore.BaseEvent `json:"-"` + // New events only use EncodedHash. However, the secret field + // is preserved to handle events older than the switch to Passwap. Secret *crypto.CryptoValue `json:"secret,omitempty"` + EncodedHash string `json:"encodedHash,omitempty"` ChangeRequired bool `json:"changeRequired"` UserAgentID string `json:"userAgentID,omitempty"` } @@ -42,7 +45,7 @@ func (e *HumanPasswordChangedEvent) UniqueConstraints() []*eventstore.EventUniqu func NewHumanPasswordChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, - secret *crypto.CryptoValue, + encodeHash string, changeRequired bool, userAgentID string, ) *HumanPasswordChangedEvent { @@ -52,7 +55,7 @@ func NewHumanPasswordChangedEvent( aggregate, HumanPasswordChangedType, ), - Secret: secret, + EncodedHash: encodeHash, ChangeRequired: changeRequired, UserAgentID: userAgentID, } @@ -268,3 +271,44 @@ func HumanPasswordCheckFailedEventMapper(event *repository.Event) (eventstore.Ev return humanAdded, nil } + +type HumanPasswordHashUpdatedEvent struct { + eventstore.BaseEvent `json:"-"` + EncodedHash string `json:"encodedHash,omitempty"` +} + +func (e *HumanPasswordHashUpdatedEvent) Data() interface{} { + return e +} + +func (e *HumanPasswordHashUpdatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *HumanPasswordHashUpdatedEvent) SetBaseEvent(base *eventstore.BaseEvent) { + e.BaseEvent = *base +} + +func NewHumanPasswordHashUpdatedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + encoded string, +) *HumanPasswordHashUpdatedEvent { + return &HumanPasswordHashUpdatedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + HumanPasswordCheckFailedType, + ), + EncodedHash: encoded, + } +} + +// SecretOrEncodedHash returns the legacy *crypto.CryptoValue if it is not nil. +// orherwise it will returns the encoded hash string. +func SecretOrEncodedHash(secret *crypto.CryptoValue, encoded string) string { + if secret != nil { + return string(secret.Crypted) + } + return encoded +} diff --git a/internal/repository/user/v1.go b/internal/repository/user/v1.go index 010e1a235..a2974bad9 100644 --- a/internal/repository/user/v1.go +++ b/internal/repository/user/v1.go @@ -15,6 +15,7 @@ const ( UserV1PasswordCodeSentType = userV1PasswordEventTypePrefix + "code.sent" UserV1PasswordCheckSucceededType = userV1PasswordEventTypePrefix + "check.succeeded" UserV1PasswordCheckFailedType = userV1PasswordEventTypePrefix + "check.failed" + UserV1PasswordHashUpdatedType = userV1PasswordEventTypePrefix + "hash.updated" userV1EmailEventTypePrefix = userEventTypePrefix + "email." UserV1EmailChangedType = userV1EmailEventTypePrefix + "changed" diff --git a/internal/static/i18n/bg.yaml b/internal/static/i18n/bg.yaml index 695007888..959c5fbbf 100644 --- a/internal/static/i18n/bg.yaml +++ b/internal/static/i18n/bg.yaml @@ -122,6 +122,8 @@ Errors: Empty: Паролата е празна Invalid: Паролата е невалидна NotSet: Потребителят не е задал парола + NotChanged: Паролата не е променена + NotSupported: Хеш кодирането на паролата не се поддържа PasswordComplexityPolicy: NotFound: Политиката за парола не е намерена MinLength: Паролата е твърде кратка @@ -506,6 +508,15 @@ Errors: TokenCreationFailed: Неуспешно създаване на токен InvalidToken: Знакът за намерение е невалиден OtherUser: Намерение, предназначено за друг потребител + AuthRequest: + AlreadyExists: Auth Request вече съществува + NotExisting: Auth Request не съществува + WrongLoginClient: Auth Request, създаден от друг клиент за влизане + OIDCSession: + RefreshTokenInvalid: Токенът за опресняване е невалиден + Token: + Invalid: Токенът е невалиден + Expired: Токенът е изтекъл AggregateTypes: action: Действие diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 846e09dff..929ce1db6 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -120,6 +120,8 @@ Errors: Empty: Passwort ist leer Invalid: Passwort ungültig NotSet: Benutzer hat kein Passwort gesetzt + NotChanged: Passwort nicht geändert + NotSupported: Passwort-Hash-Kodierung wird nicht unterstützt PasswordComplexityPolicy: NotFound: Passwort Policy konnte nicht gefunden werden MinLength: Passwort ist zu kurz @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: Tokenerstellung schlug fehl InvalidToken: Intent Token ist ungültig OtherUser: Intent ist für anderen Benutzer gedacht + AuthRequest: + AlreadyExists: Auth Request existiert bereits + NotExisting: Auth Request existiert nicht + WrongLoginClient: Auth Request wurde von einem anderen Login-Client erstellt + OIDCSession: + RefreshTokenInvalid: Refresh Token ist ungültig + Token: + Invalid: Token ist ungültig + Expired: Token ist abgelaufen + InvalidClient: Token wurde nicht für diesen Client ausgestellt AggregateTypes: action: Action diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 5986651ea..f623dc213 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -73,8 +73,8 @@ Errors: NotFound: Profile not found NotChanged: Profile not changed Empty: Profile is empty - FirstNameEmpty: First name in profile is empty - LastNameEmpty: Last name in profile is empty + FirstNameEmpty: Given name in profile is empty + LastNameEmpty: Family name in profile is empty IDMissing: Profile ID is missing Email: NotFound: Email not found @@ -120,6 +120,8 @@ Errors: Empty: Password is empty Invalid: Password is invalid NotSet: User has not set a password + NotChanged: Password not changed + NotSupported: Password hash encoding not supported PasswordComplexityPolicy: NotFound: Password policy not found MinLength: Password is too short @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: Token creation failed InvalidToken: Intent Token is invalid OtherUser: Intent meant for another user + AuthRequest: + AlreadyExists: Auth Request already exists + NotExisting: Auth Request does not exist + WrongLoginClient: Auth Request created by other login client + OIDCSession: + RefreshTokenInvalid: Refresh Token is invalid + Token: + Invalid: Token is invalid + Expired: Token is expired + InvalidClient: Token was not issued for this client AggregateTypes: action: Action diff --git a/internal/static/i18n/es.yaml b/internal/static/i18n/es.yaml index 1adb10763..097bd9e7c 100644 --- a/internal/static/i18n/es.yaml +++ b/internal/static/i18n/es.yaml @@ -120,6 +120,8 @@ Errors: Empty: La contraseña está vacía Invalid: La contraseña no es válida NotSet: El usuario no ha establecido una contraseña + NotChanged: Contraseña no modificada + NotSupported: No se admite la codificación hash de contraseña PasswordComplexityPolicy: NotFound: Política de contraseñas no encontrada MinLength: La contraseña es demasiado corta @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: Fallo en la creación del token InvalidToken: El token de la intención no es válido OtherUser: Destinado a otro usuario + AuthRequest: + AlreadyExists: Auth Request ya existe + NotExisting: Auth Request no existe + WrongLoginClient: Auth Request creado por otro cliente de inicio de sesión + OIDCSession: + RefreshTokenInvalid: El token de refresco no es válido + Token: + Invalid: El token no es válido + Expired: El token ha caducado + InvalidClient: El token no ha sido emitido para este cliente AggregateTypes: action: Acción diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index 5789a815c..7fba4deaf 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -120,6 +120,8 @@ Errors: Empty: Le mot de passe est vide Invalid: Le mot de passe n'est pas valide NotSet: L'utilisateur n'a pas défini de mot de passe + NotChanged: Mot de passe non modifié + NotSupported: Encodage de hachage de mot de passe non pris en charge PasswordComplexityPolicy: NotFound: Politique de mot de passe non trouvée MinLength: Le mot de passe est trop court @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: La création du token a échoué InvalidToken: Le jeton d'intention n'est pas valide OtherUser: Intention destinée à un autre utilisateur + AuthRequest: + AlreadyExists: Auth Request existe déjà + NotExisting: Auth Request n'existe pas + WrongLoginClient: Auth Request créé par un autre client de connexion + OIDCSession: + RefreshTokenInvalid: Le jeton de rafraîchissement n'est pas valide + Token: + Invalid: Le jeton n'est pas valide + Expired: Le jeton est expiré + InvalidClient: Le token n'a pas été émis pour ce client AggregateTypes: action: Action diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index 4e51b0fc3..4981dc307 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -120,6 +120,8 @@ Errors: Empty: La password è vuota Invalid: La password non è valida NotSet: L'utente non ha impostato una password + NotChanged: Password non modificata + NotSupported: Codifica hash password non supportata PasswordComplexityPolicy: NotFound: Impostazioni di complessità password non trovati MinLength: La password è troppo corta @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: creazione del token fallita InvalidToken: Il token dell'intento non è valido OtherUser: Intento destinato a un altro utente + AuthRequest: + AlreadyExists: Auth Request esiste già + NotExisting: Auth Request non esiste + WrongLoginClient: Auth Request creato da un altro client di accesso + OIDCSession: + RefreshTokenInvalid: Refresh Token non è valido + Token: + Invalid: Token non è valido + Expired: Token è scaduto + InvalidClient: Il token non è stato emesso per questo cliente AggregateTypes: action: Azione diff --git a/internal/static/i18n/ja.yaml b/internal/static/i18n/ja.yaml index ed6d070d1..d0ba74e27 100644 --- a/internal/static/i18n/ja.yaml +++ b/internal/static/i18n/ja.yaml @@ -112,6 +112,8 @@ Errors: Empty: パスワードは空です Invalid: 無効なパスワードです NotSet: パスワードが未設置です + NotChanged: パスワードは変更されていません + NotSupported: パスワードハッシュエンコードはサポートされていません PasswordComplexityPolicy: NotFound: パスワードポリシーが見つかりません MinLength: パスワードが短すぎます @@ -477,6 +479,16 @@ Errors: TokenCreationFailed: トークンの作成に失敗しました InvalidToken: インテントのトークンが無効である OtherUser: 他のユーザーを意図している + AuthRequest: + AlreadyExists: AuthRequestはすでに存在する + NotExisting: AuthRequest が存在しません + WrongLoginClient: 他のログインクライアントによって作成された AuthRequest + OIDCSession: + RefreshTokenInvalid: 無効なリフレッシュトークンです + Token: + Invalid: トークンが無効です + Expired: トークンの有効期限が切れている + InvalidClient: トークンが発行されていません AggregateTypes: action: アクション diff --git a/internal/static/i18n/mk.yaml b/internal/static/i18n/mk.yaml new file mode 100644 index 000000000..a02b79dc9 --- /dev/null +++ b/internal/static/i18n/mk.yaml @@ -0,0 +1,1200 @@ +Errors: + Internal: Се случи внатрешна грешка + NoChangesFound: Нема промени + OriginNotAllowed: Овој "Origin" не е дозволен + IDMissing: Недостасува ID + ResourceOwnerMissing: Недостасува Организацијата на сопственик на ресурсот + RemoveFailed: Не можеше да се отстрани + ProjectionName: + Invalid: Невалидно име на проекција + Assets: + EmptyKey: Клучот на активот е празен + Store: + NotInitialized: Складиштето на активите не е иницијализирано + NotConfigured: Складиштето на активите не е конфигурирано + Bucket: + Internal: Внатрешна грешка при креирање на кофата + AlreadyExists: Кофата веќе постои + CreateFailed: Кофата не беше креирана + ListFailed: Кофите не можат да се прочитаат + RemoveFailed: Кофата не беше избришана + SetPublicFailed: Не може да се постави кофата како јавна + Object: + PutFailed: Објектот не е креиран + GetFailed: Објектот не може да се прочита + NotFound: Објектот не е пронајден + PresignedTokenFailed: Не може да се креира потпишан токен + ListFailed: Листата на објекти не може да се прочита + RemoveFailed: Објектот не може да се отстрани + Limit: + ExceedsDefault: Лимитот го надминува стандардниот лимит + Language: + NotParsed: Јазикот не може да се парсира + OIDCSettings: + NotFound: OIDC конфигурацијата не е пронајдена + AlreadyExists: OIDC конфигурацијата веќе постои + SecretGenerator: + AlreadyExists: Генератор на тајни веќе постои + TypeMissing: Недостасува типот на генераторот на тајни + NotFound: Генераторот на тајни не е пронајден + SMSConfig: + NotFound: SMS конфигурацијата не е пронајдена + AlreadyActive: SMS конфигурацијата е веќе активна + AlreadyDeactivated: SMS конфигурацијата е веќе деактивирана + SMTPConfig: + NotFound: SMTP конфигурацијата не е пронајдена + AlreadyExists: SMTP конфигурацијата веќе постои + SenderAdressNotCustomDomain: Адресата на испраќачот мора да биде конфигурирана како прилагоден домен на инстанцата. + Notification: + NoDomain: Не е пронајден домен за пораката + User: + NotFound: Корисникот не е пронајден + AlreadyExists: Корисникот веќе постои + NotFoundOnOrg: Корисникот не е пронајден во избраната организација + NotAllowedOrg: Корисникот не е член на бараната организација + UserIDMissing: ID на корисник е празно + UserIDWrong: "Корисникот во барањето не се совпаѓа со автентицираниот корисник" + DomainPolicyNil: Политиката на организацијата е празна + EmailAsUsernameNotAllowed: Е-поштата не е дозволена како корисничко име + Invalid: Податоците на корисникот се невалидни + DomainNotAllowedAsUsername: Доменот е веќе резервиран и не може да се користи + AlreadyInactive: Корисникот е веќе неактивен + NotInactive: Корисникот не е неактивен + CantDeactivateInitial: Корисник со состојба почетен може само да биде избришан, а не и деактивиран + ShouldBeActiveOrInitial: Корисникот не е активен или почетен + AlreadyInitialised: Корисникот е веќе иницијализиран + NotInitialised: Корисникот не е сè уште иницијализиран + NotLocked: Корисникот не е заклучен + NoChanges: Не се пронајдени промени + InitCodeNotFound: Кодот за иницијализација не е пронајден + UsernameNotChanged: Корисничкото име не е променето + InvalidURLTemplate: Шаблонот за URL е невалиден + Profile: + NotFound: Профилот не е пронајден + NotChanged: Профилот не е променет + Empty: Профилот е празен + FirstNameEmpty: Името во профилот е празно + LastNameEmpty: Презимето во профилот е празно + IDMissing: ID на профилот е празно + Email: + NotFound: Е-поштата не е пронајдена + Invalid: Е-поштата е невалидна + AlreadyVerified: Е-поштата е веќе верифицирана + NotChanged: Е-поштата не е променета + Empty: Е-поштата е празна + IDMissing: ID на е-поштата е празно + Phone: + NotFound: Телефонскиот број не е пронајден + Invalid: Телефонскиот број е невалиден + AlreadyVerified: Телефонскиот број веќе е верифициран + Empty: Телефонскиот број е празен + NotChanged: Телефонскиот број не е променет + Address: + NotFound: Адресата не е пронајдена + NotChanged: Адресата не е променета + Machine: + Key: + NotFound: Machine key не е пронајден + AlreadyExisting: Machine key веќе постои + Secret: + NotExisting: Тајната не постои + Invalid: Тајната е невалидна + CouldNotGenerate: Тајната не може да биде генерирана + PAT: + NotFound: Личниот токен за пристап не е пронајден + NotHuman: Корисникот мора да биде личност + NotMachine: Корисникот мора да биде технички + WrongType: Не е дозволено за овој тип на корисник + NotAllowedToLink: Корисникот не е дозволено да се поврзе со надворешен провајдер за најава + Username: + AlreadyExists: Корисничкото име е веќе зафатено + Reserved: Корисничкото име е веќе зафатено + Empty: Корисничкото име е празно + Code: + Empty: Кодот е празен + NotFound: Кодот не е пронајден + Expired: Кодот е истечен + GeneratorAlgNotSupported: Неподдржан алгоритам за генерато + Password: + NotFound: Лозинката не е пронајдена + Empty: Лозинката е празна + Invalid: Невалидна лозинка + NotSet: Корисникот нема поставено лозинка + NotChanged: Лозинката не е променета + NotSupported: Не е поддржано хаш-кодирањето на лозинката + PasswordComplexityPolicy: + NotFound: Политиката за комплексност на лозинката не е пронајдена + MinLength: Лозинката е прекратка + MinLengthNotAllowed: Дадената минимална должина не е дозволена + HasLower: Лозинката мора да содржи мала буква + HasUpper: Лозинката мора да содржи голема буква + HasNumber: Лозинката мора да содржи број + HasSymbol: Лозинката мора да содржи симбол + ExternalIDP: + Invalid: Невалиден надворешен IDP + IDPConfigNotExisting: IDP не е валиден за оваа организација + NotAllowed: Надворешниоте IDP не е дозволен на оваа организација + MinimumExternalIDPNeeded: Мора да се додаде најмалку еден надворешен IDP + AlreadyExists: Надворешниот IDP е веќе зафатен + NotFound: Надворешниот IDP не е пронајден + MFA: + OTP: + AlreadyReady: Мултифактор OTP (Еднократна Лозинка) e веќе поставен + NotExisting: Мултифактор OTP (Еднократна Лозинка) не постои + NotReady: Мултифактор OTP (Еднократна Лозинка) не е подготвен + InvalidCode: Невалиден код + U2F: + NotExisting: U2F не постои + Passwordless: + NotExisting: Најава без лозинка не постои + WebAuthN: + NotFound: WebAuthN токенот не може да биде пронајден + BeginRegisterFailed: Почетокот на регистрацијата на WebAuthN не успеа + MarshalError: Грешка при претворање на податоците + ErrorOnParseCredential: Грешка при анализа на податоците за верификација + CreateCredentialFailed: Грешка при креирање на верификациски податоци + BeginLoginFailed: Почетокот на најавувањето на WebAuthN не успеа + ValidateLoginFailed: Грешка при валидација на податоците за најавување + CloneWarning: Креденцијалите може да бидат клонирани + RefreshToken: + Invalid: Токенот за обновување е невалиден + NotFound: Токенот за обновување не е пронајден + Instance: + NotFound: Инстанцата не е пронајдена + AlreadyExists: Инстанцата веќе постои + NotChanged: Инстанцата не е променета + Org: + AlreadyExists: Името на организацијата е веќе зафатено + Invalid: Организацијата е невалидна + AlreadyDeactivated: Организацијата е веќе деактивирана + AlreadyActive: Организацијата е веќе активна + Empty: Организацијата е празна + NotFound: Организацијата не е пронајдена + NotChanged: Организацијата не е променета + DefaultOrgNotDeletable: Стандардната организација не смее да биде избришана + ZitadelOrgNotDeletable: Организацијата со ZITADEL проект не смее да биде избришана + InvalidDomain: Невалиден домен + DomainMissing: Недостасува домен + DomainNotOnOrg: Доменот не постои во организацијата + DomainNotVerified: Доменот не е верифициран + DomainAlreadyVerified: Доменот е веќе верифициран + DomainVerificationTypeInvalid: Типот на верификација на доменот е невалиден + DomainVerificationMissing: Верификацијата на доменот сè уште не е започната + DomainVerificationFailed: Верификацијата на доменот не успеа + PrimaryDomainNotDeletable: Примарниот домен не смее да биде избришан + DomainNotFound: Доменот не е пронајден + MemberIDMissing: Недостасува ID на членот + MemberNotFound: Членот на организацијата не е пронајден + InvalidMember: Членот на организацијата е невалиден + UserIDMissing: Недостасува ID на корисникот + PolicyAlreadyExists: Политиката веќе постои + PolicyNotExisting: Политиката не постои + IdpInvalid: Валидноста на конфигурацијата за надворешни IDP е невалидна + IdpNotExisting: Конфигурацијата за надворешни IDP не постои + OIDCConfigInvalid: Валидноста на конфигурацијата за OIDC IDP е невалидна + IdpIsNotOIDC: Конфигурацијата за IDP не е од тип OIDC + Domain: + AlreadyExists: Доменот веќе постои + InvalidCharacter: Дозволени се само алфанумерички знаци, . и - се дозволени за домен + IDP: + InvalidSearchQuery: Невалидно пребарување + LoginPolicy: + NotFound: Политиката за најавување не е пронајдена + Invalid: Политиката за најавување е невалидна + RedirectURIInvalid: Невалиден стандарден URI за пренасочување + NotExisting: Политиката за најавување не постои + AlreadyExists: Политиката за најавување веќе постои + IdpProviderAlreadyExisting: IDP веќе постои + IdpProviderNotExisting: IDP не постои + RegistrationNotAllowed: Не е дозволена регистрација + UsernamePasswordNotAllowed: Не е дозволено најавување со корисничко име / лозинка + MFA: + AlreadyExists: Мултифакторот веќе постои + NotExisting: Мултифакторот не постои + Unspecified: Невалиден мултифактор + MailTemplate: + NotFound: Стандардниот шаблон за е-пошта не е пронајден + NotChanged: Стандардниот шаблон за е-пошта не е променет + AlreadyExists: Стандардниот шаблон за е-пошта веќе постои + Invalid: Стандардниот шаблон за е-пошта е невалиден + CustomMessageText: + NotFound: Стандардниот текст на пораката не е пронајден + NotChanged: Стандардниот текст на пораката не е променет + AlreadyExists: Стандардниот текст на пораката веќе постои + Invalid: Стандардниот текст на пораката е невалиден + PasswordComplexityPolicy: + NotFound: Политиката за комплексност на лозинката не е пронајдена + Empty: Политиката за комплексност на лозинката е празна + NotExisting: Политиката за комплексност на лозинката не постои + AlreadyExists: Политиката за комплексност на лозинката веќе постои + PasswordLockoutPolicy: + NotFound: Политиката за заклучување на лозинката не е пронајдена + Empty: Политиката за заклучување на лозинката е празна + NotExisting: Политиката за заклучување на лозинката не постои + AlreadyExists: Политиката за заклучување на лозинката веќе постои + PasswordAgePolicy: + NotFound: Политиката за важност на лозинката не е пронајдена + Empty: Политиката за важност на лозинката е празна + NotExisting: Политиката за важност на лозинката не постои + AlreadyExists: Политиката за важност на лозинката веќе постои + OrgIAMPolicy: + Empty: Политиката за IAM на организацијата е празна + NotExisting: Политиката за IAM на организацијата не постои + AlreadyExists: Политиката за IAM на организацијата веќе постои + NotificationPolicy: + NotFound: Политиката за известување не е пронајдена + NotChanged: Политиката за известување не е променета + AlreadyExists: Политиката за известување веќе постои + LabelPolicy: + NotFound: Приватната политика за ознаките не е пронајдена + NotChanged: Приватната политика за ознаките не е променета + Project: + ProjectIDMissing: Недостасува ID на проектот + AlreadyExists: Проектот веќе постои во организацијата + OrgNotExisting: Организацијата не постои + UserNotExisting: Корисникот не постои + CouldNotGenerateClientSecret: Не може да се генерира клиентскиот таен клуч + Invalid: Проектот е невалиден + NotActive: Проектот не е активен + NotInactive: Проектот не е деактивиран + NotFound: Проектот не е пронајден + UserIDMissing: Недостасува ID на корисникот + Member: + NotFound: Членот на проектот не е пронајден + Invalid: Членот на проектот е невалиден + AlreadyExists: Членот на проектот веќе постои + NotExisting: Членот на проектот не постои + MinimumOneRoleNeeded: Потребно е барем една улога да биде додадена + Role: + AlreadyExists: Улогата веќе постои + Invalid: Улогата е невалидна + NotExisting: Улогата не постои + IDMissing: Недостасува ID + App: + AlreadyExists: Апликацијата веќе постои + NotFound: Апликацијата не е пронајдена + Invalid: Апликацијата е невалидна + NotExisting: Апликацијата не постои + NotActive: Апликацијата не е активна + NotInactive: Апликацијата не е неактивна + OIDCConfigInvalid: OIDC конфигурацијата е невалидна + APIConfigInvalid: API конфигурацијата е невалидна + SAMLConfigInvalid: SAML конфигурацијата е невалидна + IsNotOIDC: Апликацијата не е тип OIDC + IsNotAPI: Апликацијата не е тип API + IsNotSAML: Апликацијата не е тип SAML + SAMLMetadataMissing: Недостасуваат SAML метаподатоци + SAMLMetadataFormat: Грешка во форматот на SAML метаподатоците + SAMLEntityIDAlreadyExisting: SAML EntityID веќе постои + OIDCAuthMethodNoSecret: Избраниот OIDC метод за автентикација не бара таен клуч + APIAuthMethodNoSecret: Избраниот API метод за автентикација не бара таен клуч + AuthMethodNoPrivateKeyJWT: Избраниот метод за автентикација не бара приватен клуч + ClientSecretInvalid: Клиентскиот таен клуч е невалиден + Key: + AlreadyExisting: Клучот за апликацијата веќе постои + NotFound: Клучот за апликацијата не е пронајден + RequiredFieldsMissing: Некои задолжителни полиња недостасуваат + Grant: + AlreadyExists: Овластувањето за проектот веќе постои + NotFound: Овластувањето не е пронајдено + Invalid: Овластувањето за проектот е невалидно + NotExisting: Овластувањето за проектот не постои + HasNotExistingRole: Една улога не постои на проектот + NotActive: Овластувањето за проектот не е активно + NotInactive: Овластувањето за проектот не е неактивно + IAM: + NotFound: Инстанцата не е пронајдена + Member: + RolesNotChanged: Улогите не се променети + MemberInvalid: Членот е невалиден + MemberAlreadyExisting: Членот веќе постои + MemberNotExisting: Членот не постои + IDMissing: ID недостасува + IAMProjectIDMissing: ID на IAM проектот недостасува + IamProjectAlreadySet: ID на IAM проектот веќе е поставена + IdpInvalid: IDP конфигурацијата е невалидна + IdpNotExisting: IDP конфигурацијата не постои + OIDCConfigInvalid: OIDC конфигурацијата е невалидна + IdpIsNotOIDC: IDP конфигурацијата не е од типот oidc + LoginPolicyInvalid: Политиката за најавување е невалидна + LoginPolicyNotExisting: Политиката за најавување не постои + IdpProviderInvalid: Доставувачот на идентитетот е невалиден + LoginPolicy: + NotFound: Стандардната политика за најавување не е пронајдена + NotChanged: Стандардната политика за најавување не е променета + NotExisting: Стандардната политика за најавување не постои + AlreadyExists: Стандардната политика за најавување веќе постои + RedirectURIInvalid: Стандардниот URI за пренасочување не е валиден + MFA: + AlreadyExists: Мултифакторот веќе постои + NotExisting: Мултифакторот не постои + Unspecified: Мултифакторот не е валиден + IDP: + AlreadyExists: Доставувачот на идентитетот веќе постои + NotExisting: Доставувачот на идентитетот не постои + Invalid: Невалиден доставувач на идентитетот + IDPConfig: + AlreadyExists: Конфигурацијата на доставувачот на идентитетот веќе постои + NotInactive: Конфигурацијата на доставувачот на идентитетот не е неактивна + NotActive: Конфигурацијата на доставувачот на идентитетот не е активна + LabelPolicy: + NotFound: Стандардната политика за приватни ознаки не е пронајдена + NotChanged: Стандардната политика за приватни ознаки не е променета + MailTemplate: + NotFound: Стандардниот шаблон за е-пошта не е пронајден + NotChanged: Стандардниот шаблон за е-пошта не е променет + AlreadyExists: Стандардниот шаблон за е-пошта веќе постои + Invalid: Стандардниот шаблон за е-пошта е невалиден + CustomMessageText: + NotFound: Стандардниот текст на пораката не е пронајден + NotChanged: Стандардниот текст на пораката не е променет + AlreadyExists: Стандардниот текст на пораката веќе постои + Invalid: Стандардниот текст на пораката е невалиден + PasswordComplexityPolicy: + NotFound: Стандардната политика за сложеност на лозинка не е пронајдена + NotExisting: Стандардната политика за сложеност на лозинка не постои + AlreadyExists: Стандардната политика за сложеност на лозинка веќе постои + Empty: Стандардната политика за сложеност на лозинка е празна + NotChanged: Стандардната политика за сложеност на лозинка не е променета + PasswordAgePolicy: + NotFound: Стандардната политика за важност на лозинка не е пронајдена + NotExisting: Стандардната политика за важност на лозинка не постои + AlreadyExists: Стандардната политика за важност на лозинка веќе постои + Empty: Стандардната политика за важност на лозинка е празна + NotChanged: Стандардната политика за важност на лозинка не е променета + PasswordLockoutPolicy: + NotFound: Стандардната политика за заклучување на лозинка не е пронајдена + NotExisting: Стандардната политика за заклучување на лозинка не постои + AlreadyExists: Стандардната политика за заклучување на лозинка веќе постои + Empty: Стандардната политика за заклучување на лозинка е празна + NotChanged: Стандардната политика за заклучување на лозинка не е променета + DomainPolicy: + NotFound: Политиката на IAM за организацијата не е пронајдена + Empty: Политиката на IAM за организацијата е празна + NotExisting: Политиката на IAM за организацијата не постои + AlreadyExists: Политиката на IAM за организацијата веќе постои + NotChanged: Политиката на IAM за организацијата не е променета + NotificationPolicy: + NotFound: Стандардната политика за известување не е пронајдена + NotChanged: Стандардната политика за известување не е променета + AlreadyExists: Стандардната политика за известување веќе постои + Policy: + AlreadyExists: Политиката веќе постои + Label: + Invalid: + PrimaryColor: Главната боја не е валидна хексадецимална вредност + BackgroundColor: Бојата на позадина не е валидна хексадецимална вредност + WarnColor: Предупредувачката боја не е валидна хексадецимална вредност + FontColor: Бојата на фонтот не е валидна хексадецимална вредност + PrimaryColorDark: Главната боја (темен режим) не е валидна хексадецимална вредност + BackgroundColorDark: Бојата на позадина (темен режим) не е валидна хексадецимална вредност + WarnColorDark: Предупредувачката боја (темен режим) не е валидна хексадецимална вредност + FontColorDark: Бојата на фонтот (темен режим) не е валидна хексадецимална вредност + UserGrant: + AlreadyExists: Овластувањето на корисникот веќе постои + NotFound: Овластувањето на корисникот не е пронајдено + Invalid: Овластувањето на корисникот е невалидно + NotChanged: Овластувањето на корисникот не е променето + IDMissing: ID недостасува + NotActive: Овластувањето на корисникот не е активно + NotInactive: Овластувањето на корисникот не е неактивно + NoPermissionForProject: Корисникот нема овластувања за овој проект + RoleKeyNotFound: Улогата не е пронајдена + Member: + AlreadyExists: Членот веќе постои + IDPConfig: + AlreadyExists: Конфигурацијата на IDP веќе постои + NotExisting: Конфигурацијата на IDP не постои + Changes: + NotFound: Нема пронајдена историја + AuditRetention: Историјата е надвор од задржувањето на аудитот + Token: + NotFound: Токенот не е пронајден + UserSession: + NotFound: Корисничката сесија не е пронајдена + Key: + ExpireBeforeNow: Датумот на истекување е во минатото + Login: + LoginPolicy: + MFA: + ForceAndNotConfigured: Мултифакторската проверка е конфигурирана како задолжителна, но нема конфигурирани можностите за неа. Ве молиме контактирајте го вашиот системски администратор. + Step: + Started: + AlreadyExists: Веќе постои започнат чекор + Done: + AlreadyExists: Веќе постои комплетиран чекор + CustomText: + AlreadyExists: Прилагоден текст веќе постои + Invalid: Прилагодениот текст е невалиден + NotFound: Прилагодениот текст не е пронајден + TranslationFile: + ReadError: Грешка при читање на преводниот документ + MergeError: Преводниот документ не може да се спои со прилагодените преводи + NotFound: Преводниот документ не постои + Metadata: + NotFound: Метаподатоците не се пронајдени + NoData: Листата на метаподатоци е празна + Invalid: Метаподатоците се невалидни + KeyNotExisting: Еден или повеќе клучеви не постојат + Action: + Invalid: Акцијата е невалидна + NotFound: Акцијата не е пронајдена + NotActive: Акцијата не е активна + NotInactive: Акцијата не е неактивна + MaxAllowed: Не се дозволени дополнителни активни акции + Flow: + FlowTypeMissing: FlowType не е наведен + Empty: Flow е веќе празен + WrongTriggerType: TriggerType не е валиден + NoChanges: Нема промени + ActionIDsNotExist: ActionIDs не постојат + Query: + CloseRows: SQL наредбата не може да се заврши + SQLStatement: SQL наредбата не може да се креира + InvalidRequest: Барањето е невалидно + Quota: + AlreadyExists: Веќе постои квота за оваа единица + NotFound: Квотата не е пронајдена за оваа единица + Invalid: + CallURL: URL-то за повик на квота е невалидно + Percent: Процентот на квота е помал од 1 + Unimplemented: Квотите не се имплементирани за оваа единица + Amount: Износот на квотата е помал од 1 + ResetInterval: Интервалот за ресетирање на квотата е помал од една минута + Noop: Неограничена квота без известувања нема ефект + Access: + Exhausted: Квотата за автентицирани барања е исцрпена + Execution: + Exhausted: Квотата за извршување во секунди е исцрпена + LogStore: + Access: + StorageFailed: Неуспешно зачувување на логовите за пристап во базата на податоци + ScanFailed: Неуспешно пребарување за автентицирани барања + Execution: + StorageFailed: Неуспешно зачувување на логовите за извршување на акции во базата на податоци + ScanFailed: Неуспешно пребарување за времетраењето на акции + Session: + NotExisting: Сесијата не постои + Terminated: Сесијата е веќе завршена + Token: + Invalid: Токенот за сесија е невалиден + Passkey: + NoChallenge: Сесија без предизвик за passkey + Intent: + IDPMissing: ID на IDP недостасува во барањето + SuccessURLMissing: URL за успех недостасува во барањето + FailureURLMissing: URL за неуспех недостасува во барањето + StateMissing: Параметарот State недостасува во барањето + NotStarted: Намерата не е започната или веќе завршена + NotSucceeded: Намерата не е успешна + TokenCreationFailed: Неуспешно креирање на токен + InvalidToken: Токенот за намера е невалиден + OtherUser: Намерата е за друг корисник + AuthRequest: + AlreadyExists: Барањето за автентикација веќе постои + NotExisting: Барањето за автентикација не постои + WrongLoginClient: Барањето за автификација беше креирано од друг клиент за најавување + OIDCSession: + RefreshTokenInvalid: Токенот за освежување е неважечки + Token: + Invalid: токенот е неважечки + Expired: токенот е истечен + InvalidClient: Токен не беше издаден на овој клиент + +AggregateTypes: + action: Акција + instance: Инстанца + key_pair: Пар на клучеви + org: Организација + project: Проект + user: Корисник + usergrant: Овластување на корисник + quota: Квота + +EventTypes: + user: + added: Додаден корисник + selfregistered: Корисникот се регистрираше сам + initialization: + code: + added: Генериран е код за иницијализација + sent: Кодот за иницијализација е испратен + check: + succeeded: Проверката на иницијализацијата е успешна + failed: Проверката на иницијализацијата е неуспешна + token: + added: Креиран е токен за пристап + removed: Токенот за пристап е отстранет + username: + reserved: Корисничкото име е резервирано + released: Корисничкото име е ослободено + changed: Корисничкото име е променето + email: + reserved: Е-поштата е резервирана + released: Е-поштата е ослободена + changed: Е-поштата е променета + verified: Е-поштата е верифицирана + verification: + failed: Верификацијата на е-поштата е неуспешна + code: + added: Генериран е код за верификација на е-пошта + sent: Кодот за верификација на е-пошта е испратен + machine: + added: Додаден технички корисник + changed: Променет технички корисник + key: + added: Клучето е додаден + removed: Клучот е отстранет + secret: + set: Тајната е додадена + removed: Тајната е отстрането + check: + succeeded: Проверката на тајната е успешна + failed: Проверката на тајната е неуспешна + human: + added: Додадено лице + selfregistered: Лицето се регистрирало само + avatar: + added: Додаден аватар + removed: Отстранет аватар + initialization: + code: + added: Генериран код за иницијализација + sent: Испратен код за иницијализација + check: + succeeded: Проверката на иницијализацијата е успешна + failed: Проверката на иницијализацијата е неуспешна + username: + reserved: Корисничкото име е резервирано + released: Корисничкото име е ослободено + email: + changed: Променета е-пошта + verified: Верифицирана е-пошта + verification: + failed: Верификацијата на е-поштата е неуспешна + code: + added: Генериран код за верификација на е-пошта + sent: Испратен код за верификација на е-пошта + password: + changed: Променета лозинка + code: + added: Генериран код за лозинка + sent: Испратен код за лозинка + check: + succeeded: Проверката на лозинката е успешна + failed: Проверката на лозинката е неуспешна + externallogin: + check: + succeeded: Надворешното најавување е успешно + externalidp: + added: Додаден надворешен IDP + removed: Отстранет надворешен IDP + cascade: + removed: Отстранета каскадата на надворешни IDP + phone: + changed: Променет број на телефон + verified: Верифициран број на телефон + verification: + failed: Верификацијата на бројот на телефонот е неуспешна + code: + added: Генериран код за број на телефон + sent: Испратен код за број на телефон + removed: Отстранет број на телефон + profile: + changed: Променет кориснички профил + address: + changed: Променета адреса на корисник + mfa: + otp: + added: Додаден мултифактор OTP + verified: Верифициран мултифактор OTP + removed: Отстранет мултифактор OTP + check: + succeeded: Проверката на мултифактор OTP е успешна + failed: Проверката на мултифактор OTP е неуспешна + u2f: + token: + added: Додаден мултифактор U2F токен + verified: Верифициран мултифактор U2F токен + removed: Отстранет мултифактор U2F токен + begin: + login: Започната мултифактор U2F проверка + check: + succeeded: Проверката на мултифактор U2F токен е успешна + failed: Проверката на мултифактор U2F токен е неуспешна + signcount: + changed: Checksum на мултифактор U2F токен е променет + init: + skipped: Прескокната иницијализација на мултифактор + passwordless: + token: + added: Додаден токен за најава без лозинка + verified: Верифициран токен за најава без лозинка + removed: Отстранет токен за најава без лозинка + begin: + login: Започната проверка на најава без лозинка + check: + succeeded: Проверката на најава без лозинка е успешна + failed: Проверката на најава без лозинка е неуспешна + signcount: + changed: Checksum на токенот за најава без лозинка е променет + initialization: + code: + added: Додаден код за иницијализација на најава без лозинка + sent: Испратен код за иницијализација на најава без лозинка + requested: Побаран код за иницијализација на најава без лозинка + check: + succeeded: Проверката на кодот за иницијализација на најава без лозинка е успешна + failed: Проверката на кодот за иницијализација на најава без лозинка е неуспешна + signed: + out: Корисникот се одјави + refresh: + token: + added: Креиран е токен за обновување + renewed: Обновен е токен за обновување + removed: Отстранет е токен за обновување + locked: Корисникот е заклучен + unlocked: Корисникот е отклучен + deactivated: Корисникот е деактивиран + reactivated: Корисникот е повторно активиран + removed: Корисникот е отстранет + password: + changed: Лозинката е променета + code: + added: Генериран е код за лозинка + sent: Кодот за лозинка е испратен + check: + succeeded: Проверката на лозинката е успешна + failed: Проверката на лозинката е неуспешна + phone: + changed: Бројот на телефонот е променет + verified: Бројот на телефонот е верифициран + verification: + failed: Верификацијата на бројот на телефонот е неуспешна + code: + added: Генериран е код за број на телефон + sent: Кодот за број на телефон е испратен + removed: Бројот на телефонот е отстранет + profile: + changed: Променет профил на корисникот + address: + changed: Променета адреса на корисникот + mfa: + otp: + added: Додаден мултифактор OTP + verified: Верифициран мултифактор OTP + removed: Отстранет мултифактор OTP + check: + succeeded: Проверката на мултифактор OTP е успешна + failed: Проверката на мултифактор OTP е неуспешна + init: + skipped: Прескокната иницијализација на мултифактор OTP + init: + skipped: Прескокната иницијализација на мултифактор + signed: + out: Корисникот се одјави + grant: + added: Додадено овластување + changed: Променето овластување + removed: Отстрането овластување + deactivated: Овластувањето е деактивирано + reactivated: Овластувањето е повторно активирано + reserved: Овластувањето е задржано + released: Овластувањето е ослободено + cascade: + removed: Отстрането овластување + changed: Променето овластување + metadata: + set: Поставени кориснички метаподатоци + removed: Отстранети кориснички метаподатоци + removed.all: Сите кориснички метаподатоци се отстранети + domain: + claimed: Доменот е преземен + claimed.sent: Испратено е известување за преземање на домен + pat: + added: Додаден личен токен за пристап + removed: Отстранет личен токен за пристап + org: + added: Додадена организација + changed: Променета организација + deactivated: Организацијата е деактивирана + reactivated: Организацијата е повторно активирана + removed: Организацијата е отстранета + domain: + added: Додаден домен + verification: + added: Додадена верификација на домен + failed: Верификацијата на доменот е неуспешна + verified: Доменот е верифициран + removed: Доменот е отстранет + primary: + set: Поставен примарен домен + reserved: Доменот е резервиран + released: Доменот е ослободен + name: + reserved: Името на организацијата е резервирано + released: Името на организацијата е ослободено + member: + added: Додаден член на организацијата + changed: Променет член на организацијата + removed: Отстранет член на организацијата + cascade: + removed: Отстранета каскада на членови на организацијата + iam: + policy: + added: Додадена системска политика + changed: Променета системска политика + removed: Отстранета системска политика + idp: + config: + added: Додадена конфигурација за IDP + changed: Променета конфигурација за IDP + removed: Отстранета конфигурација за IDP + deactivated: Деактивирана конфигурација за IDP + reactivated: Повторно активирана конфигурација за IDP + oidc: + config: + added: Додадена OIDC конфигурација за IDP + changed: Променета OIDC конфигурација за IDP + saml: + config: + added: Додадена SAML конфигурација за IDP + changed: Променета SAML конфигурација за IDP + jwt: + config: + added: Додадена JWT конфигурација за IDP + changed: Променета JWT конфигурација за IDP + customtext: + set: Поставен прилагоден текст + removed: Отстранет прилагоден текст + template: + removed: Отстранет шаблон за прилагоден текст + policy: + login: + added: Додадена политика за најавување + changed: Променета политика за најавување + removed: Отстранета политика за најавување + idpprovider: + added: Додаден провајдер на идентитет во политика за најавување + removed: Отстранет провајдер на идентитет од политика за најавување + cascade: + removed: Отстранет каскада на провајдери на идентитет во политика за најавување + secondfactor: + added: Додаден втор фактор во политика за најавување + removed: Отстранет втор фактор од политика за најавување + multifactor: + added: Додаден мултифактор во политика за најавување + removed: Отстранет мултифактор од политика за најавување + password: + complexity: + added: Додадена политика за сложеност на лозинка + changed: Променета политика за сложеност на лозинка + removed: Отстранета политика за сложеност на лозинка + age: + added: Додадена политика за важност на лозинка + changed: Променета политика за важност на лозинка + removed: Отстранета политика за важност на лозинка + lockout: + added: Додадена политика за заклучување на лозинка + changed: Променета политика за заклучување на лозинка + removed: Отстранета политика за заклучување на лозинка + label: + added: Додадена политика за ознака + changed: Променета политика за ознака + activated: Активирана политика за ознака + removed: Отстранета политика за ознака + logo: + added: Додаден лого во политика за ознака + removed: Отстрането лого од политика за ознака + dark: + added: Додадено лого (темен режим) во политика за ознака + removed: Отстрането лого (темен режим) од политика за ознака + icon: + added: Додадена икона во политика за ознака + removed: Отстранета икона од политика за ознака + dark: + added: Додадена икона (темен режим) во политика за ознака + removed: Отстранета икона (темен режим) од политика за ознака + font: + added: Додаден фонт во политика за ознака + removed: Отстранет фонт од политика за ознака + assets: + removed: Отстранети ресурси од политика за ознака + privacy: + added: Додадена политика за приватност и услови на користење + changed: Променета политика за приватност и услови на користење + removed: Отстранета политика за приватност и услови на користење + domain: + added: Додадена политика за домен + changed: Променета политика за домен + removed: Отстранета политика за домен + lockout: + added: Додадена политика за заклучување + changed: Променета политика за заклучување + removed: Отстранета политика за заклучување + notification: + added: Додадена политика за известување + changed: Променета политика за известување + removed: Отстранета политика за известување + flow: + trigger_actions: + set: Поставени акции + cascade: + removed: Отстранета каскада акции + removed: Отстранети акции + cleared: Исчистен Flow + mail: + template: + added: Додаден шаблон за е-пошта + changed: Променет шаблон за е-пошта + removed: Отстранет шаблон за е-пошта + text: + added: Додаден текст за е-пошта + changed: Променет текст за е-пошта + removed: Отстранет текст за е-пошта + metadata: + removed: Отстранети метаподатоци + removed.all: Отстранети сите метаподатоци + set: Поставени метаподатоци + project: + added: Додаден проект + changed: Променет проект + deactivated: Проектот е деактивиран + reactivated: Проектот е повторно активиран + removed: Проектот е отстранет + member: + added: Додаден член на проектот + changed: Променет член на проектот + removed: Отстранет член на проектот + cascade: + removed: Отстранетa каскада членови на проектот + role: + added: Додадена улога на проектот + changed: Променета улога на проектот + removed: Отстранета улога на проектот + grant: + added: Додаден овластување за менаџирање + changed: Променето овластување за менаџирање + removed: Отстрането овластување за менаџирање + deactivated: Деактивирано овластување за менаџирање + reactivated: Повторно активирано овластување за менаџирање + cascade: + changed: Променетa каскада овластувања за менаџирање + member: + added: Додаден член на пристапот за менаџирање + changed: Променет член на пристапот за менаџирање + removed: Отстранет член на пристапот за менаџирање + cascade: + removed: Отстранети членови на пристапот за менаџирање + application: + added: Додадена апликација + changed: Променета апликација + removed: Отстранета апликација + deactivated: Деактивирана апликација + reactivated: Повторно активирана апликација + oidc: + secret: + check: + succeeded: Проверката на OIDC клиентска тајна е успешна + failed: Проверката на OIDC клиентска тајна е неуспешна + key: + added: Додаден клуч за апликацијата + removed: Отстранет клуч за апликацијата + config: + saml: + added: Додадена SAML конфигурација + changed: Променета SAML конфигурација + oidc: + added: Додадена OIDC конфигурација + changed: Променета OIDC конфигурација + secret: + changed: Променета OIDC тајна + api: + added: Додадена API конфигурација + changed: Променета API конфигурација + secret: + changed: Променета API тајна + policy: + password: + complexity: + added: Додадена политика за сложеност на лозинка + changed: Променета политика за сложеност на лозинка + age: + added: Додадена политика за важност на лозинка + changed: Променета политика за важност на лозинка + lockout: + added: Додадена политика за заклучување на лозинка + changed: Променета политика за заклучување на лозинка + iam: + setup: + started: Започнато ZITADEL поставување + done: Завршено ZITADEL поставување + global: + org: + set: Поставена глобална организација + project: + iam: + set: Поставен ZITADEL проект + member: + added: Додаден ZITADEL член + changed: Променет ZITADEL член + removed: Отстранет ZITADEL член + cascade: + removed: Отстранети ZITADEL членови + idp: + config: + added: Додадена IDP конфигурација + changed: Променета IDP конфигурација + removed: Отстранета IDP конфигурација + deactivated: Деактивирана IDP конфигурација + reactivated: Повторно активирана IDP конфигурација + oidc: + config: + added: Додадена OIDC IDP конфигурација + changed: Променета OIDC IDP конфигурација + saml: + config: + added: Додадена SAML IDP конфигурација + changed: Променета SAML IDP конфигурација + jwt: + config: + added: Додадена JWT конфигурација на IDP + changed: Променета JWT конфигурација на IDP + customtext: + set: Текстот е поставен + removed: Текстот е отстранет + policy: + login: + added: Додадена стандардна политика за најавување + changed: Променета стандардна политика за најавување + idpprovider: + added: Додаден IDP во стандардната политика за најавување + removed: Отстранет IDP од стандардната политика за најавување + label: + added: Додадена политика за ознака + changed: Променета политика за ознака + activated: Активирана политика за ознака + logo: + added: Додаден лого на политика за ознака + removed: Отстрането лого од политика за ознака + dark: + added: Додадено лого (темен режим) на политика за ознака + removed: Отстрането лого (темен режим) од политика за ознака + icon: + added: Додадена икона на политика за ознака + removed: Отстранета икона од политика за ознака + dark: + added: Додадена икона (темен режим) на политика за ознака + removed: Отстранета икона (темен режим) од политика за ознака + font: + added: Додаден фонт во политика за ознака + removed: Отстранет фонт од политика за ознака + assets: + removed: Отстранети ресурси од политика за ознака + default: + language: + set: Поставен стандарден јазик + oidc: + settings: + added: Додадена OIDC конфигурација + changed: Променета OIDC конфигурација + removed: Отстранета OIDC конфигурација + secret: + generator: + added: Додаден генератор на тајни + changed: Променет генератор на тајни + removed: Отстранет генератор на тајни + smtp: + config: + added: Додадена SMTP конфигурација + changed: Променета SMTP конфигурација + password: + changed: Променена тајна на SMTP конфигурација + sms: + config: + twilio: + added: Додаден Twilio SMS провајдер + changed: Променет Twilio SMS провајдер + token: + changed: Променет токен на Twilio SMS провајдер + removed: Отстранет Twilio SMS провајдер + activated: Активиран Twilio SMS провајдер + deactivated: Деактивиран Twilio SMS провајдер + key_pair: + added: Додаден пар на клучеви + certificate: + added: Додаден сертификат + action: + added: Додадена акција + changed: Променета акција + deactivated: Деактивирана акција + reactivated: Реактивирана акција + removed: Отстранета акција + instance: + added: Додадена инстанца + changed: Променета инстанца + customtext: + removed: Отстранет прилагоден текст + set: Поставен прилагоден текст + template: + removed: Отстранет шаблон на прилагоден текст + default: + language: + set: Поставен стандарден јазик + org: + set: Поставена стандардна организација + domain: + added: Додаден домен + primary: + set: Поставен примарен домен + removed: Отстранет домен + iam: + console: + set: Поставена апликација на ZITADEL конзола + project: + set: Поставен проект на ZITADEL + mail: + template: + added: Додаден е-пошта шаблон + changed: Променет е-пошта шаблон + text: + added: Додаден е-пошта текст + changed: Променет е-пошта текст + member: + added: Додаден член на инстанцата + changed: Променет член на инстанцата + removed: Отстранет член на инстанцата + cascade: + removed: Отстранети членови на инстанцата + notification: + provider: + debug: + fileadded: Додаден провајдер за откривање на грешки во датотека + filechanged: Променет провајдер за откривање на грешки во датотека + fileremoved: Отстранет провајдер за откривање на грешки во датотека + logadded: Додаден провајдер за откривање на грешки во логови + logchanged: Променет провајдер за откривање на грешки во логови + logremoved: Отстранет провајдер за откривање на грешки во логови + oidc: + settings: + added: Додадени OIDC поставки + changed: Променети OIDC поставки + policy: + domain: + added: Додадена политика за домен + changed: Променета политика за домен + label: + activated: Активирана политика за ознаки + added: Додадена политика за ознаки + assets: + removed: Отстранети средства од политиката за ознаки + changed: Променета политика за ознаки + font: + added: Додаден фонт на политиката за ознаки + removed: Отстранет фонт од политиката за ознаки + icon: + added: Додадена икона на политиката за ознаки + removed: Отстранета икона од политиката за ознаки + dark: + added: Додадена темна икона на политиката за ознаки + removed: Отстранета темна икона од политиката за ознаки + logo: + added: Додаден лого на политиката за ознаки + removed: Отстрането лого од политиката за ознаки + dark: + added: Додадено темно лого на политиката за ознаки + removed: Отстрането темно лого од политиката за ознаки + lockout: + added: Додадена политика за заклучување + changed: Променета политика за заклучување + login: + added: Додадена политика за најавување + changed: Променета политика за најавување + idpprovider: + added: Додаден провајдер на идентитети во политиката за најавување + cascade: + removed: Отстранет провајдер на идентитети од политиката за најавување + removed: Отстранет провајдер на идентитети од политиката за најавување + multifactor: + added: Додадена мултифакторска автентикација во политиката за најавување + removed: Отстранета мултифакторска автентикација од политиката за најавување + secondfactor: + added: Додаден втор фактор во политиката за најавување + removed: Отстранет втор фактор од политиката за најавување + password: + age: + added: Додадена политика за возраст на лозинка + changed: Променета политика за возраст на лозинка + complexity: + added: Додадена политика за комплексност на лозинка + changed: Отстранета политика за комплексност на лозинка + privacy: + added: Додадена политика за приватност + changed: Променета политика за приватност + security: + set: Поставена политика за безбедност + removed: Отстранети инстанци + secret: + generator: + added: Додаден генератор на тајни + changed: Променет генератор на тајни + removed: Отстранет генератор на тајни + sms: + configtwilio: + activated: Активирана Twilio SMS конфигурација + added: Додадена Twilio SMS конфигурација + changed: Променета Twilio SMS конфигурација + deactivated: Деактивирана Twilio SMS конфигурација + removed: Отстранета Twilio SMS конфигурација + token: + changed: Променет токен на Twilio SMS конфигурацијата + smtp: + config: + added: Додадена SMTP конфигурација + changed: Променета SMTP конфигурација + password: + changed: Променета лозинка на SMTP конфигурацијата + removed: Отстранета SMTP конфигурација + +Application: + OIDC: + UnsupportedVersion: Вашата OIDC верзија не е поддржана + V1: + NotCompliant: Вашата конфигурација не е во согласност и се разликува од OIDC 1.0 стандардот. + NoRedirectUris: Мора да биде регистриран барем еден URI за пренасочување. + NotAllCombinationsAreAllowed: Конфигурацијата е во согласност, но не се дозволени сите можни комбинации. + Code: + RedirectUris: + HttpOnlyForWeb: Грант типот code дозволува само HTTP URI за пренасочување за веб апликации. + CustomOnlyForNative: Грант типот code дозволува само сопствени URI за пренасочување за нативни апликации (на пример appname:// ). + Implicit: + RedirectUris: + CustomNotAllowed: Грант типот implicit не дозволува сопствени URI за пренасочување. + HttpNotAllowed: Грант типот implicit не дозволува HTTP URI за пренасочување. + HttpLocalhostOnlyForNative: Пренасочувањето кон URI-то http://localhost е дозволено само за нативни апликации. + Native: + AuthMethodType: + NotNone: Нативните апликации треба да имаат authmethodtype none. + RedirectUris: + MustBeHttpLocalhost: URI-тата за пренасочување мора да почнуваат со ваш протокол, http://127.0.0.1, http://[::1] или http://localhost. + UserAgent: + AuthMethodType: + NotNone: Апликациите на кориснички агент треба да имаат authmethodtype none. + GrantType: + Refresh: + NoAuthCode: Refresh Token е дозволен само во комбинација со Authorization Code. + +Action: + Flow: + Type: + Unspecified: Неодредено + ExternalAuthentication: Надворешна автентикација + CustomiseToken: Комплемент на токенот + InternalAuthentication: Внатрешна автентикација + TriggerType: + Unspecified: Неодредено + PostAuthentication: По автентикација + PreCreation: Пред креирање + PostCreation: По креирање + PreUserinfoCreation: Пред креирање на кориснички информации + PreAccessTokenCreation: Пред креирање на токен за пристап diff --git a/internal/static/i18n/pl.yaml b/internal/static/i18n/pl.yaml index 9e907dcbe..3e48f4582 100644 --- a/internal/static/i18n/pl.yaml +++ b/internal/static/i18n/pl.yaml @@ -120,6 +120,8 @@ Errors: Empty: Hasło jest puste Invalid: Hasło jest nieprawidłowe NotSet: Użytkownik nie ustawił hasła + NotChanged: Hasło nie zostało zmienione + NotSupported: Kodowanie skrótu hasła nie jest obsługiwane PasswordComplexityPolicy: NotFound: Polityka hasła nie znaleziona MinLength: Hasło jest zbyt krótkie @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: Tworzenie tokena nie powiodło się InvalidToken: Token intencji jest nieprawidłowy OtherUser: Intencja przeznaczona dla innego użytkownika + AuthRequest: + AlreadyExists: Auth Request już istnieje + NotExisting: Auth Request nie istnieje + WrongLoginClient: Auth Request utworzony przez innego klienta logowania + OIDCSession: + RefreshTokenInvalid: Refresh Token jest nieprawidłowy + Token: + Invalid: Token jest nieprawidłowy + Expired: Token wygasł + InvalidClient: Token nie został wydany dla tego klienta AggregateTypes: action: Działanie diff --git a/internal/static/i18n/pt.yaml b/internal/static/i18n/pt.yaml new file mode 100644 index 000000000..963191eb5 --- /dev/null +++ b/internal/static/i18n/pt.yaml @@ -0,0 +1,1195 @@ +Errors: + Internal: Ocorreu um erro interno + NoChangesFound: Nenhuma alteração encontrada + OriginNotAllowed: Esta "Origem" não é permitida + IDMissing: ID ausente + ResourceOwnerMissing: Organização proprietária de recurso ausente + RemoveFailed: Não foi possível remover + ProjectionName: + Invalid: Nome de projeção inválido + Assets: + EmptyKey: A chave do recurso está vazia + Store: + NotInitialized: Armazenamento de recursos não inicializado + NotConfigured: Armazenamento de recursos não configurado + Bucket: + Internal: Erro interno ao criar o bucket + AlreadyExists: O bucket já existe + CreateFailed: Não foi possível criar o bucket + ListFailed: Não foi possível ler os buckets + RemoveFailed: Não foi possível excluir o bucket + SetPublicFailed: Não foi possível definir o bucket como público + Object: + PutFailed: Não foi possível criar o objeto + GetFailed: Não foi possível ler o objeto + NotFound: Objeto não encontrado + PresignedTokenFailed: Não foi possível criar o token assinado + ListFailed: Não foi possível ler a lista de objetos + RemoveFailed: Não foi possível remover o objeto + Limit: + ExceedsDefault: Limite excede o limite padrão + Language: + NotParsed: Não foi possível analisar o idioma + OIDCSettings: + NotFound: Configuração OIDC não encontrada + AlreadyExists: Configuração OIDC já existe + SecretGenerator: + AlreadyExists: Gerador de segredos já existe + TypeMissing: Tipo de gerador de segredos ausente + NotFound: Gerador de segredos não encontrado + SMSConfig: + NotFound: Configuração de SMS não encontrada + AlreadyActive: Configuração de SMS já está ativa + AlreadyDeactivated: Configuração de SMS já está desativada + SMTPConfig: + NotFound: Configuração de SMTP não encontrada + AlreadyExists: Configuração de SMTP já existe + SenderAdressNotCustomDomain: O endereço do remetente deve ser configurado como um domínio personalizado na instância. + Notification: + NoDomain: Nenhum domínio encontrado para a mensagem + User: + NotFound: Usuário não pôde ser encontrado + AlreadyExists: Usuário já existe + NotFoundOnOrg: Usuário não pôde ser encontrado na organização escolhida + NotAllowedOrg: O usuário não é membro da organização requerida + UserIDMissing: ID do usuário ausente + UserIDWrong: "Usuário da solicitação não é igual ao usuário autenticado" + DomainPolicyNil: Política da organização está vazia + EmailAsUsernameNotAllowed: O email não é permitido como nome de usuário + Invalid: Dados do usuário são inválidos + DomainNotAllowedAsUsername: O domínio já está reservado e não pode ser usado + AlreadyInactive: Usuário já está inativo + NotInactive: O usuário não está inativo + CantDeactivateInitial: O usuário com estado inicial só pode ser excluído, não desativado + ShouldBeActiveOrInitial: O usuário não está ativo ou no estado inicial + AlreadyInitialised: O usuário já está inicializado + NotInitialised: O usuário ainda não está inicializado + NotLocked: O usuário não está bloqueado + NoChanges: Nenhuma alteração encontrada + InitCodeNotFound: Código de inicialização não encontrado + UsernameNotChanged: Nome de usuário não alterado + InvalidURLTemplate: O modelo de URL é inválido + Profile: + NotFound: Perfil não encontrado + NotChanged: Perfil não alterado + Empty: Perfil está vazio + FirstNameEmpty: Nome fornecido no perfil está vazio + LastNameEmpty: Sobrenome fornecido no perfil está vazio + IDMissing: ID do perfil está faltando + Email: + NotFound: Email não encontrado + Invalid: O email é inválido + AlreadyVerified: O email já foi verificado + NotChanged: Email não alterado + Empty: O email está vazio + IDMissing: ID do email está faltando + Phone: + NotFound: Telefone não encontrado + Invalid: O telefone é inválido + AlreadyVerified: O telefone já foi verificado + Empty: O telefone está vazio + NotChanged: Telefone não alterado + Address: + NotFound: Endereço não encontrado + NotChanged: Endereço não alterado + Machine: + Key: + NotFound: Chave de máquina não encontrada + AlreadyExisting: Chave de máquina já existe + Secret: + NotExisting: Segredo não existe + Invalid: Segredo é inválido + CouldNotGenerate: Não foi possível gerar o segredo + PAT: + NotFound: Token de Acesso Pessoal não encontrado + NotHuman: O usuário deve ser pessoal + NotMachine: O usuário deve ser técnico + WrongType: Não permitido para este tipo de usuário + NotAllowedToLink: O usuário não tem permissão para vincular com provedor de login externo + Username: + AlreadyExists: Nome de usuário já está em uso + Reserved: Nome de usuário já está em uso + Empty: Nome de usuário está vazio + Code: + Empty: Código está vazio + NotFound: Código não encontrado + Expired: Código expirou + GeneratorAlgNotSupported: Algoritmo do gerador não suportado + Password: + NotFound: Senha não encontrada + Empty: Senha está vazia + Invalid: Senha é inválida + NotSet: O usuário não definiu uma senha + PasswordComplexityPolicy: + NotFound: Política de complexidade de senha não encontrada + MinLength: A senha é muito curta + MinLengthNotAllowed: O comprimento mínimo fornecido não é permitido + HasLower: A senha deve conter letras minúsculas + HasUpper: A senha deve conter letras maiúsculas + HasNumber: A senha deve conter números + HasSymbol: A senha deve conter caracteres especiais + ExternalIDP: + Invalid: IDP externo inválido + IDPConfigNotExisting: Provedor de IDP inválido para esta organização + NotAllowed: IDP externo não permitido nesta organização + MinimumExternalIDPNeeded: Pelo menos um IDP deve ser adicionado + AlreadyExists: IDP externo já está em uso + NotFound: IDP externo não encontrado + MFA: + OTP: + AlreadyReady: OTP (OneTimePassword) de autenticação multifator já está configurado + NotExisting: OTP (OneTimePassword) de autenticação multifator não existe + NotReady: OTP (OneTimePassword) de autenticação multifator não está pronto + InvalidCode: Código inválido + U2F: + NotExisting: U2F não existe + Passwordless: + NotExisting: Autenticação sem senha não existe + WebAuthN: + NotFound: Token WebAuthN não pôde ser encontrado + BeginRegisterFailed: Falha ao iniciar o registro do WebAuthN + MarshalError: Erro ao processar os dados + ErrorOnParseCredential: Erro ao analisar os dados de credenciais + CreateCredentialFailed: Erro ao criar as credenciais + BeginLoginFailed: Falha ao iniciar o login do WebAuthN + ValidateLoginFailed: Erro ao validar as credenciais de login + CloneWarning: As credenciais podem ser clonadas + RefreshToken: + Invalid: Refresh Token inválido + NotFound: Refresh Token não encontrado + Instance: + NotFound: Instância não encontrada + AlreadyExists: Instância já existe + NotChanged: Instância não alterada + Org: + AlreadyExists: Nome da organização já está em uso + Invalid: Organização é inválida + AlreadyDeactivated: Organização já está desativada + AlreadyActive: Organização já está ativa + Empty: Organização está vazia + NotFound: Organização não encontrada + NotChanged: Organização não alterada + DefaultOrgNotDeletable: A organização padrão não pode ser excluída + ZitadelOrgNotDeletable: A organização com o projeto ZITADEL não pode ser excluída + InvalidDomain: Domínio inválido + DomainMissing: Domínio ausente + DomainNotOnOrg: O domínio não existe na organização + DomainNotVerified: O domínio não foi verificado + DomainAlreadyVerified: O domínio já foi verificado + DomainVerificationTypeInvalid: O tipo de verificação do domínio é inválido + DomainVerificationMissing: A verificação do domínio ainda não foi iniciada + DomainVerificationFailed: Falha na verificação do domínio + PrimaryDomainNotDeletable: O domínio principal não pode ser excluído + DomainNotFound: Domínio não encontrado + MemberIDMissing: ID do membro ausente + MemberNotFound: Membro da organização não encontrado + InvalidMember: Membro da organização é inválido + UserIDMissing: ID do usuário ausente + PolicyAlreadyExists: Política já existe + PolicyNotExisting: Política não existe + IdpInvalid: Configuração de IDP é inválida + IdpNotExisting: Configuração de IDP não existe + OIDCConfigInvalid: Configuração de IDP OIDC é inválida + IdpIsNotOIDC: A configuração de IDP não é do tipo OIDC + Domain: + AlreadyExists: Domínio já existe + InvalidCharacter: Apenas caracteres alfanuméricos, . e - são permitidos para um domínio + IDP: + InvalidSearchQuery: Consulta de pesquisa inválida + LoginPolicy: + NotFound: Política de login não encontrada + Invalid: Política de login é inválida + RedirectURIInvalid: O URI de redirecionamento padrão é inválido + NotExisting: Política de login não existe + AlreadyExists: Política de login já existe + IdpProviderAlreadyExisting: Provedor de identidade já existe + IdpProviderNotExisting: Provedor de identidade não existe + RegistrationNotAllowed: O registro não é permitido + UsernamePasswordNotAllowed: O login com nome de usuário/senha não é permitido + MFA: + AlreadyExists: Autenticação multifator já existe + NotExisting: Autenticação multifator não existe + Unspecified: Autenticação multifator inválida + MailTemplate: + NotFound: Modelo de email padrão não encontrado + NotChanged: Modelo de email padrão não foi alterado + AlreadyExists: Modelo de email padrão já existe + Invalid: Modelo de email padrão é inválido + CustomMessageText: + NotFound: Texto de mensagem padrão não encontrado + NotChanged: Texto de mensagem padrão não foi alterado + AlreadyExists: Texto de mensagem padrão já existe + Invalid: Texto de mensagem padrão é inválido + PasswordComplexityPolicy: + NotFound: Política de complexidade de senha não encontrada + Empty: Política de complexidade de senha está vazia + NotExisting: Política de complexidade de senha não existe + AlreadyExists: Política de complexidade de senha já existe + PasswordLockoutPolicy: + NotFound: Política de Bloqueio de Senha não encontrada + Empty: A Política de Bloqueio de Senha está vazia + NotExisting: A Política de Bloqueio de Senha não existe + AlreadyExists: A Política de Bloqueio de Senha já existe + PasswordAgePolicy: + NotFound: Política de Idade de Senha não encontrada + Empty: A Política de Idade de Senha está vazia + NotExisting: A Política de Idade de Senha não existe + AlreadyExists: A Política de Idade de Senha já existe + OrgIAMPolicy: + Empty: A Política de IAM da Organização está vazia + NotExisting: A Política de IAM da Organização não existe + AlreadyExists: A Política de IAM da Organização já existe + NotificationPolicy: + NotFound: Política de Notificação não encontrada + NotChanged: Política de Notificação não alterada + AlreadyExists: Política de Notificação já existe + LabelPolicy: + NotFound: Política de Rótulo Privado não encontrada + NotChanged: Política de Rótulo Privado não foi alterada + Project: + ProjectIDMissing: ID do Projeto ausente + AlreadyExists: Projeto já existe na organização + OrgNotExisting: A organização não existe + UserNotExisting: O usuário não existe + CouldNotGenerateClientSecret: Não foi possível gerar o segredo do cliente + Invalid: O projeto é inválido + NotActive: O projeto não está ativo + NotInactive: O projeto não está desativado + NotFound: Projeto não encontrado + UserIDMissing: ID do usuário ausente + Member: + NotFound: Membro do projeto não encontrado + Invalid: O membro do projeto é inválido + AlreadyExists: Membro do projeto já existe + NotExisting: O membro do projeto não existe + MinimumOneRoleNeeded: Pelo menos uma função deve ser adicionada + Role: + AlreadyExists: A função já existe + Invalid: A função é inválida + NotExisting: A função não existe + IDMissing: ID ausente + App: + AlreadyExists: O aplicativo já existe + NotFound: Aplicativo não encontrado + Invalid: Aplicativo inválido + NotExisting: O aplicativo não existe + NotActive: O aplicativo não está ativo + NotInactive: O aplicativo não está inativo + OIDCConfigInvalid: A configuração OIDC é inválida + APIConfigInvalid: A configuração da API é inválida + SAMLConfigInvalid: A configuração SAML é inválida + IsNotOIDC: O aplicativo não é do tipo OIDC + IsNotAPI: O aplicativo não é do tipo API + IsNotSAML: O aplicativo não é do tipo SAML + SAMLMetadataMissing: O metadados SAML está ausente + SAMLMetadataFormat: Erro de formato nos metadados SAML + SAMLEntityIDAlreadyExisting: O EntityID SAML já existe + OIDCAuthMethodNoSecret: O método de autenticação OIDC escolhido não requer um segredo + APIAuthMethodNoSecret: O método de autenticação da API escolhido não requer um segredo + AuthMethodNoPrivateKeyJWT: O método de autenticação escolhido não requer uma chave + ClientSecretInvalid: O segredo do cliente é inválido + Key: + AlreadyExisting: Chave do aplicativo já existente + NotFound: Chave do aplicativo não encontrada + RequiredFieldsMissing: Alguns campos obrigatórios estão faltando + Grant: + AlreadyExists: A concessão do projeto já existe + NotFound: Concessão não encontrada + Invalid: A concessão do projeto é inválida + NotExisting: A concessão do projeto não existe + HasNotExistingRole: Uma função não existe no projeto + NotActive: A concessão do projeto não está ativa + NotInactive: A concessão do projeto não está inativa + IAM: + NotFound: Instância não encontrada + Member: + RolesNotChanged: As funções não foram alteradas + MemberInvalid: O membro é inválido + MemberAlreadyExisting: O membro já existe + MemberNotExisting: O membro não existe + IDMissing: ID ausente + IAMProjectIDMissing: ID do projeto IAM ausente + IamProjectAlreadySet: O ID do projeto IAM já foi definido + IdpInvalid: A configuração de IDP é inválida + IdpNotExisting: A configuração de IDP não existe + OIDCConfigInvalid: A configuração de IDP OIDC é inválida + IdpIsNotOIDC: A configuração de IDP não é do tipo oidc + LoginPolicyInvalid: A Política de Login é inválida + LoginPolicyNotExisting: A Política de Login não existe + IdpProviderInvalid: O Provedor de Identidade é inválido + LoginPolicy: + NotFound: Política de Login padrão não encontrada + NotChanged: Política de Login padrão não foi alterada + NotExisting: Política de Login padrão não existe + AlreadyExists: Política de Login padrão já existe + RedirectURIInvalid: O URI de redirecionamento padrão é inválido + MFA: + AlreadyExists: A autenticação multifator já existe + NotExisting: A autenticação multifator não existe + Unspecified: A autenticação multifator é inválida + IDP: + AlreadyExists: O provedor de identidade já existe + NotExisting: O provedor de identidade não existe + Invalid: Provedor de identidade inválido + IDPConfig: + AlreadyExists: A configuração de provedor de identidade já existe + NotInactive: A configuração de provedor de identidade não está inativa + NotActive: A configuração de provedor de identidade não está ativa + LabelPolicy: + NotFound: Política de Rótulo Privado padrão não encontrada + NotChanged: Política de Rótulo Privado padrão não foi alterada + MailTemplate: + NotFound: Modelo de E-mail padrão não encontrado + NotChanged: Modelo de E-mail padrão não foi alterado + AlreadyExists: Modelo de E-mail padrão já existe + Invalid: O Modelo de E-mail padrão é inválido + CustomMessageText: + NotFound: Texto de Mensagem padrão não encontrado + NotChanged: Texto de Mensagem padrão não foi alterado + AlreadyExists: Texto de Mensagem padrão já existe + Invalid: O Texto de Mensagem padrão é inválido + PasswordComplexityPolicy: + NotFound: Política de Complexidade de Senha Padrão não encontrada + NotExisting: Política de Complexidade de Senha Padrão não existente + AlreadyExists: Política de Complexidade de Senha Padrão já existente + Empty: Política de Complexidade de Senha Padrão vazia + NotChanged: Política de Complexidade de Senha Padrão não foi alterada + PasswordAgePolicy: + NotFound: Política de Idade de Senha Padrão não encontrada + NotExisting: Política de Idade de Senha Padrão não existente + AlreadyExists: Política de Idade de Senha Padrão já existente + Empty: Política de Idade de Senha Padrão vazia + NotChanged: Política de Idade de Senha Padrão não foi alterada + PasswordLockoutPolicy: + NotFound: Política de Bloqueio de Senha Padrão não encontrada + NotExisting: Política de Bloqueio de Senha Padrão não existente + AlreadyExists: Política de Bloqueio de Senha Padrão já existente + Empty: Política de Bloqueio de Senha Padrão vazia + NotChanged: Política de Bloqueio de Senha Padrão não foi alterada + DomainPolicy: + NotFound: Política IAM da Organização não encontrada + Empty: Política IAM da Organização está vazia + NotExisting: Política IAM da Organização não existente + AlreadyExists: Política IAM da Organização já existe + NotChanged: Política IAM da Organização não foi alterada + NotificationPolicy: + NotFound: Política de Notificação Padrão não encontrada + NotChanged: Política de Notificação Padrão não foi alterada + AlreadyExists: Política de Notificação Padrão já existe + Policy: + AlreadyExists: Política já existe + Label: + Invalid: + PrimaryColor: A cor primária não é um valor hexadecimal válido + BackgroundColor: A cor de fundo não é um valor hexadecimal válido + WarnColor: A cor de aviso não é um valor hexadecimal válido + FontColor: A cor da fonte não é um valor hexadecimal válido + PrimaryColorDark: A cor primária (modo escuro) não é um valor hexadecimal válido + BackgroundColorDark: A cor de fundo (modo escuro) não é um valor hexadecimal válido + WarnColorDark: A cor de aviso (modo escuro) não é um valor hexadecimal válido + FontColorDark: A cor da fonte (modo escuro) não é um valor hexadecimal válido + UserGrant: + AlreadyExists: A concessão de usuário já existe + NotFound: A concessão de usuário não foi encontrada + Invalid: A concessão de usuário é inválida + NotChanged: A concessão de usuário não foi alterada + IDMissing: ID faltando + NotActive: A concessão de usuário não está ativa + NotInactive: A concessão de usuário não está desativada + NoPermissionForProject: O usuário não possui permissões neste projeto + RoleKeyNotFound: Função não encontrada + Member: + AlreadyExists: O membro já existe + IDPConfig: + AlreadyExists: Configuração de Provedor de Identidade com esse nome já existe + NotExisting: A Configuração do Provedor de Identidade não existe + Changes: + NotFound: Nenhum histórico encontrado + AuditRetention: O histórico está fora do período de retenção do registro de auditoria + Token: + NotFound: Token não encontrado + UserSession: + NotFound: Sessão do usuário não encontrada + Key: + ExpireBeforeNow: A data de expiração está no passado + Login: + LoginPolicy: + MFA: + ForceAndNotConfigured: A autenticação multifator está configurada como obrigatória, mas nenhum provedor possível está configurado. Entre em contato com o administrador do sistema. + Step: + Started: + AlreadyExists: A etapa já foi iniciada + Done: + AlreadyExists: A etapa já foi concluída + CustomText: + AlreadyExists: O texto personalizado já existe + Invalid: O texto personalizado é inválido + NotFound: O texto personalizado não foi encontrado + TranslationFile: + ReadError: Erro ao ler o arquivo de tradução + MergeError: O arquivo de tradução não pôde ser mesclado com as traduções personalizadas + NotFound: O arquivo de tradução não existe + Metadata: + NotFound: Metadados não encontrados + NoData: A lista de metadados está vazia + Invalid: Os metadados são inválidos + KeyNotExisting: Uma ou mais chaves não existem + Action: + Invalid: A ação é inválida + NotFound: A ação não foi encontrada + NotActive: A ação não está ativa + NotInactive: A ação não está inativa + MaxAllowed: Não são permitidas ações adicionais ativas + Flow: + FlowTypeMissing: O tipo de fluxo está faltando + Empty: O fluxo já está vazio + WrongTriggerType: O tipo de acionador é inválido + NoChanges: Sem alterações + ActionIDsNotExist: Os IDs de ação não existem + Query: + CloseRows: A instrução SQL não pôde ser concluída + SQLStatement: Não foi possível criar a instrução SQL + InvalidRequest: O pedido é inválido + Quota: + AlreadyExists: Cota já existe para esta unidade + NotFound: Cota não encontrada para esta unidade + Invalid: + CallURL: A URL de chamada da cota é inválida + Percent: A porcentagem da cota é menor que 1 + Unimplemented: As cotas não são implementadas para esta unidade + Amount: A quantidade da cota é menor que 1 + ResetInterval: O intervalo de reinicialização da cota é menor que um minuto + Noop: Uma cota ilimitada sem notificações não tem efeito + Access: + Exhausted: A cota para solicitações autenticadas está esgotada + Execution: + Exhausted: A cota para segundos de execução está esgotada + LogStore: + Access: + StorageFailed: Falha ao armazenar o log de acesso no banco de dados + ScanFailed: Falha ao consultar o uso para solicitações autenticadas + Execution: + StorageFailed: Falha ao armazenar o log de execução da ação no banco de dados + ScanFailed: Falha ao consultar o uso para segundos de execução da ação + Session: + NotExisting: A sessão não existe + Terminated: A sessão já foi encerrada + Token: + Invalid: O token da sessão é inválido + Passkey: + NoChallenge: Sessão sem desafio de senha + Intent: + IDPMissing: O ID do IDP está faltando na solicitação + SuccessURLMissing: A URL de sucesso está faltando na solicitação + FailureURLMissing: A URL de falha está faltando na solicitação + StateMissing: O parâmetro de estado está faltando na solicitação + NotStarted: A intenção não foi iniciada ou já foi encerrada + NotSucceeded: A intenção não teve sucesso + TokenCreationFailed: Falha na criação do token + InvalidToken: O token da intenção é inválido + OtherUser: Intenção destinada a outro usuário + AuthRequest: + AlreadyExists: A solicitação de autenticação já existe + NotExisting: A solicitação de autenticação não existe + WrongLoginClient: A solicitação de autenticação foi criada por outro cliente de login + OIDCSession: + RefreshTokenInvalid: O Refresh Token é inválido + +AggregateTypes: + action: Ação + instance: Instância + key_pair: Par de chaves + org: Organização + project: Projeto + user: Usuário + usergrant: Concessão de usuário + quota: Cota + +EventTypes: + user: + added: Usuário adicionado + selfregistered: Usuário se registrou + initialization: + code: + added: Código de inicialização gerado + sent: Código de inicialização enviado + check: + succeeded: Verificação de inicialização bem-sucedida + failed: Verificação de inicialização falhou + token: + added: Token de acesso criado + removed: Token de acesso removido + username: + reserved: Nome de usuário reservado + released: Nome de usuário liberado + changed: Nome de usuário alterado + email: + reserved: Endereço de e-mail reservado + released: Endereço de e-mail liberado + changed: Endereço de e-mail alterado + verified: Endereço de e-mail verificado + verification: + failed: Falha na verificação do endereço de e-mail + code: + added: Código de verificação do endereço de e-mail gerado + sent: Código de verificação do endereço de e-mail enviado + machine: + added: Usuário técnico adicionado + changed: Usuário técnico alterado + key: + added: Chave adicionada + removed: Chave removida + secret: + set: Segredo definido + removed: Segredo removido + check: + succeeded: Verificação de segredo bem-sucedida + failed: Verificação de segredo falhou + human: + added: Pessoa adicionada + selfregistered: Pessoa se registrou + avatar: + added: Avatar adicionado + removed: Avatar removido + initialization: + code: + added: Código de inicialização gerado + sent: Código de inicialização enviado + check: + succeeded: Verificação de inicialização bem-sucedida + failed: Verificação de inicialização falhou + username: + reserved: Nome de usuário reservado + released: Nome de usuário liberado + email: + changed: Endereço de e-mail alterado + verified: Endereço de e-mail verificado + verification: + failed: Falha na verificação do endereço de e-mail + code: + added: Código de verificação do endereço de e-mail gerado + sent: Código de verificação do endereço de e-mail enviado + password: + changed: Senha alterada + code: + added: Código de senha gerado + sent: Código de senha enviado + check: + succeeded: Verificação de senha bem-sucedida + failed: Verificação de senha falhou + externallogin: + check: + succeeded: Login externo bem-sucedido + externalidp: + added: IDP externo adicionado + removed: IDP externo removido + cascade: + removed: Cascade de IDP externo removido + phone: + changed: Número de telefone alterado + verified: Número de telefone verificado + verification: + failed: Falha na verificação do número de telefone + code: + added: Código de verificação do número de telefone gerado + sent: Código de verificação do número de telefone enviado + removed: Número de telefone removido + profile: + changed: Perfil do usuário alterado + address: + changed: Endereço do usuário alterado + mfa: + otp: + added: OTP de autenticação multifator adicionado + verified: OTP de autenticação multifator verificado + removed: OTP de autenticação multifator removido + check: + succeeded: Verificação de OTP de autenticação multifator bem-sucedida + failed: Verificação de OTP de autenticação multifator falhou + u2f: + token: + added: Token U2F de autenticação multifator adicionado + verified: Token U2F de autenticação multifator verificado + removed: Token U2F de autenticação multifator removido + begin: + login: Verificação U2F de autenticação multifator iniciada + check: + succeeded: Verificação U2F de autenticação multifator bem-sucedida + failed: Verificação U2F de autenticação multifator falhou + signcount: + changed: O checksum do Token U2F de autenticação multifator foi alterado + init: + skipped: Inicialização multifator pulada + passwordless: + token: + added: Token para login sem senha adicionado + verified: Token para login sem senha verificado + removed: Token para login sem senha removido + begin: + login: Verificação de login sem senha iniciada + check: + succeeded: Verificação de login sem senha bem-sucedida + failed: Verificação de login sem senha falhou + signcount: + changed: O checksum do Token para login sem senha foi alterado + initialization: + code: + added: Código de inicialização sem senha adicionado + sent: Código de inicialização sem senha enviado + requested: Código de inicialização sem senha solicitado + check: + succeeded: Verificação do código de inicialização sem senha realizada com sucesso + failed: Falha na verificação do código de inicialização sem senha + signed: + out: Usuário desconectado + refresh: + token: + added: Refresh Token criado + renewed: Refresh Token renovado + removed: Refresh Token removido + locked: Usuário bloqueado + unlocked: Usuário desbloqueado + deactivated: Usuário desativado + reactivated: Usuário reativado + removed: Usuário removido + password: + changed: Senha alterada + code: + added: Código de senha gerado + sent: Código de senha enviado + check: + succeeded: Verificação de senha bem-sucedida + failed: Verificação de senha falhou + phone: + changed: Número de telefone alterado + verified: Número de telefone verificado + verification: + failed: Falha na verificação do número de telefone + code: + added: Código de verificação do número de telefone gerado + sent: Código de verificação do número de telefone enviado + removed: Número de telefone removido + profile: + changed: Perfil do usuário alterado + address: + changed: Endereço do usuário alterado + mfa: + otp: + added: OTP de autenticação multifator adicionado + verified: OTP de autenticação multifator verificado + removed: OTP de autenticação multifator removido + check: + succeeded: Verificação de OTP de autenticação multifator bem-sucedida + failed: Verificação de OTP de autenticação multifator falhou + init: + skipped: Inicialização de OTP de autenticação multifator pulada + init: + skipped: Inicialização multifator pulada + signed: + out: Usuário desconectado + grant: + added: Autorização adicionada + changed: Autorização alterada + removed: Autorização removida + deactivated: Autorização desativada + reactivated: Autorização reativada + reserved: Autorização reservada + released: Autorização liberada + cascade: + removed: Autorização removida + changed: Autorização alterada + metadata: + set: Metadados do usuário definidos + removed: Metadados do usuário removidos + removed.all: Todos os metadados do usuário removidos + domain: + claimed: Domínio reivindicado + claimed.sent: Notificação de reivindicação de domínio enviada + pat: + added: Token de Acesso Pessoal adicionado + removed: Token de Acesso Pessoal removido + org: + added: Organização adicionada + changed: Organização alterada + deactivated: Organização desativada + reactivated: Organização reativada + removed: Organização removida + domain: + added: Domínio adicionado + verification: + added: Verificação de domínio adicionada + failed: Falha na verificação de domínio + verified: Domínio verificado + removed: Domínio removido + primary: + set: Domínio principal definido + reserved: Domínio reservado + released: Domínio liberado + name: + reserved: Nome da organização reservado + released: Nome da organização liberado + member: + added: Membro da organização adicionado + changed: Membro da organização alterado + removed: Membro da organização removido + cascade: + removed: Membro da organização removido em cascata + iam: + policy: + added: Política do sistema adicionada + changed: Política do sistema alterada + removed: Política do sistema removida + idp: + config: + added: Configuração do IDP adicionada + changed: Configuração do IDP alterada + removed: Configuração do IDP removida + deactivated: Configuração do IDP desativada + reactivated: Configuração do IDP reativada + oidc: + config: + added: Configuração do IDP OIDC adicionada + changed: Configuração do IDP OIDC alterada + saml: + config: + added: Configuração do IDP SAML adicionada + changed: Configuração do IDP SAML alterada + jwt: + config: + added: Configuração do IDP JWT adicionada + changed: Configuração do IDP JWT alterada + customtext: + set: Texto personalizado definido + removed: Texto personalizado removido + template: + removed: Modelo de texto personalizado removido + policy: + login: + added: Política de login adicionada + changed: Política de login alterada + removed: Política de login removida + idpprovider: + added: Provedor de identidade adicionado à política de login + removed: Provedor de identidade removido da política de login + cascade: + removed: Remoção em cascata do provedor de identidade da política de login + secondfactor: + added: Segundo fator adicionado à política de login + removed: Segundo fator removido da política de login + multifactor: + added: Multifator adicionado à política de login + removed: Multifator removido da política de login + password: + complexity: + added: Política de complexidade de senha adicionada + changed: Política de complexidade de senha alterada + removed: Política de complexidade de senha removida + age: + added: Política de idade da senha adicionada + changed: Política de idade da senha alterada + removed: Política de idade da senha removida + lockout: + added: Política de bloqueio de senha adicionada + changed: Política de bloqueio de senha alterada + removed: Política de bloqueio de senha removida + label: + added: Política de rótulo adicionada + changed: Política de rótulo alterada + activated: Política de rótulo ativada + removed: Política de rótulo removida + logo: + added: Logotipo adicionado à política de rótulo + removed: Logotipo removido da política de rótulo + dark: + added: Logotipo (modo escuro) adicionado à política de rótulo + removed: Logotipo (modo escuro) removido da política de rótulo + icon: + added: Ícone adicionado à política de rótulo + removed: Ícone removido da política de rótulo + dark: + added: Ícone (modo escuro) adicionado à política de rótulo + removed: Ícone (modo escuro) removido da política de rótulo + font: + added: Fonte adicionada à política de rótulo + removed: Fonte removida da política de rótulo + assets: + removed: Ativos removidos da política de rótulo + privacy: + added: Política de privacidade e TOS adicionada + changed: Política de privacidade e TOS alterada + removed: Política de privacidade e TOS removida + domain: + added: Política de domínio adicionada + changed: Política de domínio alterada + removed: Política de domínio removida + lockout: + added: Política de bloqueio adicionada + changed: Política de bloqueio alterada + removed: Política de bloqueio removida + notification: + added: Política de notificação adicionada + changed: Política de notificação alterada + removed: Política de notificação removida + flow: + trigger_actions: + set: Ação definida + cascade: + removed: Ações removidas em cascata + removed: Ações removidas + cleared: Fluxo limpo + mail: + template: + added: Modelo de e-mail adicionado + changed: Modelo de e-mail alterado + removed: Modelo de e-mail removido + text: + added: Texto de e-mail adicionado + changed: Texto de e-mail alterado + removed: Texto de e-mail removido + metadata: + removed: Metadados removidos + removed.all: Todos os metadados removidos + set: Metadados definidos + project: + added: Projeto adicionado + changed: Projeto alterado + deactivated: Projeto desativado + reactivated: Projeto reativado + removed: Projeto removido + member: + added: Membro do projeto adicionado + changed: Membro do projeto alterado + removed: Membro do projeto removido + cascade: + removed: Membro do projeto removido em cascata + role: + added: Função do projeto adicionada + changed: Função do projeto alterada + removed: Função do projeto removida + grant: + added: Acesso de gerenciamento adicionado + changed: Acesso de gerenciamento alterado + removed: Acesso de gerenciamento removido + deactivated: Acesso de gerenciamento desativado + reactivated: Acesso de gerenciamento reativado + cascade: + changed: Acesso de gerenciamento alterado + member: + added: Membro do acesso de gerenciamento adicionado + changed: Membro do acesso de gerenciamento alterado + removed: Membro do acesso de gerenciamento removido + cascade: + removed: Acesso de gerenciamento removido em cascata + application: + added: Aplicativo adicionado + changed: Aplicativo alterado + removed: Aplicativo removido + deactivated: Aplicativo desativado + reactivated: Aplicativo reativado + oidc: + secret: + check: + succeeded: Verificação de segredo do cliente OIDC bem-sucedida + failed: Verificação de segredo do cliente OIDC falhou + key: + added: Chave do aplicativo adicionada + removed: Chave do aplicativo removida + config: + saml: + added: Configuração SAML adicionada + changed: Configuração SAML alterada + oidc: + added: Configuração OIDC adicionada + changed: Configuração OIDC alterada + secret: + changed: Segredo OIDC alterado + api: + added: Configuração de API adicionada + changed: Configuração de API alterada + secret: + changed: Segredo da API alterado + policy: + password: + complexity: + added: Política de complexidade de senha adicionada + changed: Política de complexidade de senha alterada + age: + added: Política de idade da senha adicionada + changed: Política de idade da senha alterada + lockout: + added: Política de bloqueio de senha adicionada + changed: Política de bloqueio de senha alterada + iam: + setup: + started: Configuração do ZITADEL iniciada + done: Configuração do ZITADEL concluída + global: + org: + set: Organização global definida + project: + iam: + set: Projeto ZITADEL definido + member: + added: Membro ZITADEL adicionado + changed: Membro ZITADEL alterado + removed: Membro ZITADEL removido + cascade: + removed: Membro ZITADEL removido em cascata + idp: + config: + added: Configuração do IDP adicionada + changed: Configuração do IDP alterada + removed: Configuração do IDP removida + deactivated: Configuração do IDP desativada + reactivated: Configuração do IDP reativada + oidc: + config: + added: Configuração do IDP OIDC adicionada + changed: Configuração do IDP OIDC alterada + saml: + config: + added: Configuração do IDP SAML adicionada + changed: Configuração do IDP SAML alterada + jwt: + config: + added: Configuração JWT do provedor de identidade adicionada + changed: Configuração JWT do provedor de identidade removida + customtext: + set: Texto definido + removed: Texto removido + policy: + login: + added: Política de login padrão adicionada + changed: Política de login padrão alterada + idpprovider: + added: Provedor de identidade adicionado à política de login padrão + removed: Provedor de identidade removido da política de login padrão + label: + added: Política de rótulo adicionada + changed: Política de rótulo alterada + activated: Política de rótulo ativada + logo: + added: Logotipo adicionado à política de rótulo + removed: Logotipo removido da política de rótulo + dark: + added: Logotipo (modo escuro) adicionado à política de rótulo + removed: Logotipo (modo escuro) removido da política de rótulo + icon: + added: Ícone adicionado à política de rótulo + removed: Ícone removido da política de rótulo + dark: + added: Ícone (modo escuro) adicionado à política de rótulo + removed: Ícone (modo escuro) removido da política de rótulo + font: + added: Fonte adicionada à política de rótulo + removed: Fonte removida da política de rótulo + assets: + removed: Ativos removidos da política de rótulo + default: + language: + set: Idioma padrão definido + oidc: + settings: + added: Configuração OIDC adicionada + changed: Configuração OIDC alterada + removed: Configuração OIDC removida + secret: + generator: + added: Gerador de segredos adicionado + changed: Gerador de segredos alterado + removed: Gerador de segredos removido + smtp: + config: + added: Configuração SMTP adicionada + changed: Configuração SMTP alterada + password: + changed: Segredo da configuração SMTP alterado + sms: + config: + twilio: + added: Provedor de SMS Twilio adicionado + changed: Provedor de SMS Twilio alterado + token: + changed: Token do provedor de SMS Twilio alterado + removed: Provedor de SMS Twilio removido + activated: Provedor de SMS Twilio ativado + deactivated: Provedor de SMS Twilio desativado + key_pair: + added: Par de chaves adicionado + certificate: + added: Certificado adicionado + action: + added: Ação adicionada + changed: Ação alterada + deactivated: Ação desativada + reactivated: Ação reativada + removed: Ação removida + instance: + added: Instância adicionada + changed: Instância alterada + customtext: + removed: Texto personalizado removido + set: Texto personalizado definido + template: + removed: Modelo de texto personalizado removido + default: + language: + set: Idioma padrão definido + org: + set: Organização padrão definida + domain: + added: Domínio adicionado + primary: + set: Domínio principal definido + removed: Domínio removido + iam: + console: + set: ZITADEL Console definido + project: + set: Projeto ZITADEL definido + mail: + template: + added: Modelo de e-mail adicionado + changed: Modelo de e-mail alterado + text: + added: Texto de e-mail adicionado + changed: Texto de e-mail alterado + member: + added: Membro da instância adicionado + changed: Membro da instância alterado + removed: Membro da instância removido + cascade: + removed: Membro da instância removido em cascata + notification: + provider: + debug: + fileadded: Provedor de notificação de arquivo de depuração adicionado + filechanged: Provedor de notificação de arquivo de depuração alterado + fileremoved: Provedor de notificação de arquivo de depuração removido + logadded: Provedor de notificação de log de depuração adicionado + logchanged: Provedor de notificação de log de depuração alterado + logremoved: Provedor de notificação de log de depuração removido + oidc: + settings: + added: Configurações OIDC adicionadas + changed: Configurações OIDC alteradas + policy: + domain: + added: Política de domínio adicionada + changed: Política de domínio alterada + label: + activated: Política de rótulo ativada + added: Política de rótulo adicionada + assets: + removed: Ativo removido da política de rótulo + changed: Política de rótulo alterada + font: + added: Fonte adicionada à política de rótulo + removed: Fonte removida da política de rótulo + icon: + added: Ícone adicionado à política de rótulo + removed: Ícone removido da política de rótulo + dark: + added: Ícone adicionado à política de rótulo (modo escuro) + removed: Ícone removido da política de rótulo (modo escuro) + logo: + added: Logotipo adicionado à política de rótulo + removed: Logotipo removido da política de rótulo + dark: + added: Logotipo adicionado à política de rótulo (modo escuro) + removed: Logotipo removido da política de rótulo (modo escuro) + lockout: + added: Política de bloqueio adicionada + changed: Política de bloqueio alterada + login: + added: Política de login adicionada + changed: Política de login alterada + idpprovider: + added: Provedor de identidade adicionado à política de login + cascade: + removed: Remoção em cascata do provedor de identidade da política de login + removed: Provedor de identidade removido da política de login + multifactor: + added: Multifator adicionado à política de login + removed: Multifator removido da política de login + secondfactor: + added: Segundo fator adicionado à política de login + removed: Segundo fator removido da política de login + password: + age: + added: Política de idade da senha adicionada + changed: Política de idade da senha alterada + complexity: + added: Política de complexidade da senha adicionada + changed: Política de complexidade da senha removida + privacy: + added: Política de privacidade adicionada + changed: Política de privacidade alterada + security: + set: Política de segurança definida + + removed: Instância removida + secret: + generator: + added: Gerador de segredos adicionado + changed: Gerador de segredos alterado + removed: Gerador de segredos removido + sms: + configtwilio: + activated: Configuração de SMS Twilio ativada + added: Configuração de SMS Twilio adicionada + changed: Configuração de SMS Twilio alterada + deactivated: Configuração de SMS Twilio desativada + removed: Configuração de SMS Twilio removida + token: + changed: Token da configuração de SMS Twilio alterado + smtp: + config: + added: Configuração SMTP adicionada + changed: Configuração SMTP alterada + password: + changed: Senha da configuração SMTP alterada + removed: Configuração SMTP removida + +Application: + OIDC: + UnsupportedVersion: Sua versão do OIDC não é suportada + V1: + NotCompliant: Sua configuração não está em conformidade e difere do padrão OIDC 1.0. + NoRedirectUris: É necessário registrar pelo menos um URI de redirecionamento. + NotAllCombinationsAreAllowed: A configuração está em conformidade, mas nem todas as combinações possíveis são permitidas. + Code: + RedirectUris: + HttpOnlyForWeb: O tipo de concessão de código permite apenas URIs de redirecionamento http para aplicativos web. + CustomOnlyForNative: O tipo de concessão de código permite apenas URIs de redirecionamento personalizados para aplicativos nativos (por exemplo, appname://). + Implicit: + RedirectUris: + CustomNotAllowed: O tipo de concessão implícita não permite URIs de redirecionamento personalizados. + HttpNotAllowed: O tipo de concessão implícita não permite URIs de redirecionamento http. + HttpLocalhostOnlyForNative: O URI de redirecionamento http://localhost só é permitido para aplicativos nativos. + Native: + AuthMethodType: + NotNone: Aplicativos nativos devem ter o tipo de método de autenticação nenhum. + RedirectUris: + MustBeHttpLocalhost: Os URIs de redirecionamento devem começar com seu próprio protocolo, http://127.0.0.1, http://[::1] ou http://localhost. + UserAgent: + AuthMethodType: + NotNone: O aplicativo de agente do usuário deve ter o tipo de método de autenticação nenhum. + GrantType: + Refresh: + NoAuthCode: O token de atualização só é permitido em combinação com o Código de Autorização. + +Action: + Flow: + Type: + Unspecified: Não especificado + ExternalAuthentication: Autenticação externa + CustomiseToken: Complementar Token + InternalAuthentication: Autenticação interna + TriggerType: + Unspecified: Não especificado + PostAuthentication: Pós-autenticação + PreCreation: Pré-criação + PostCreation: Póscriação + PreUserinfoCreation: Pré-criação de informações do usuário + PreAccessTokenCreation: Pré-criação de access token diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index 2a9f2400f..1209fd515 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -120,6 +120,8 @@ Errors: Empty: 密码为空 Invalid: 密码无效 NotSet: 用户未设置密码 + NotChanged: 密码未更改 + NotSupported: 不支持密码哈希编码 PasswordComplexityPolicy: NotFound: 未找到密码策略 MinLength: 密码太短 @@ -488,6 +490,16 @@ Errors: TokenCreationFailed: 令牌创建失败 InvalidToken: 意图令牌是无效的 OtherUser: 意图是为另一个用户准备的 + AuthRequest: + AlreadyExists: AuthRequest已经存在 + NotExisting: AuthRequest不存在 + WrongLoginClient: 其他登录客户端创建的AuthRequest + OIDCSession: + RefreshTokenInvalid: Refresh Token 无效 + Token: + Invalid: 令牌无效 + Expired: 令牌已过期 + InvalidClient: 没有为该客户发放令牌 AggregateTypes: action: 动作 diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index 672e18aef..8cb0d4346 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -170,12 +170,12 @@ func (u *UserView) MFATypesSetupPossible(level domain.MFALevel, policy *domain.L return types } -func (u *UserView) MFATypesAllowed(level domain.MFALevel, policy *domain.LoginPolicy) ([]domain.MFAType, bool) { +func (u *UserView) MFATypesAllowed(level domain.MFALevel, policy *domain.LoginPolicy, isInternalAuthentication bool) ([]domain.MFAType, bool) { types := make([]domain.MFAType, 0) required := true switch level { default: - required = policy.ForceMFA + required = domain.RequiresMFA(policy.ForceMFA, policy.ForceMFALocalOnly, isInternalAuthentication) fallthrough case domain.MFALevelSecondFactor: if policy.HasSecondFactors() { diff --git a/internal/user/repository/eventsourcing/model/password.go b/internal/user/repository/eventsourcing/model/password.go index 1699c8c99..6c7414111 100644 --- a/internal/user/repository/eventsourcing/model/password.go +++ b/internal/user/repository/eventsourcing/model/password.go @@ -15,6 +15,7 @@ type Password struct { es_models.ObjectRoot Secret *crypto.CryptoValue `json:"secret,omitempty"` + EncodedHash string `json:"encodedHash,omitempty"` ChangeRequired bool `json:"changeRequired,omitempty"` } diff --git a/internal/user/repository/view/model/notify_user.go b/internal/user/repository/view/model/notify_user.go index a2ff48deb..7390bc504 100644 --- a/internal/user/repository/view/model/notify_user.go +++ b/internal/user/repository/view/model/notify_user.go @@ -128,6 +128,6 @@ func (u *NotifyUser) setPasswordData(event *models.Event) error { logging.Log("MODEL-dfhw6").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(nil, "MODEL-BHFD2", "could not unmarshal data") } - u.PasswordSet = password.Secret != nil + u.PasswordSet = password.Secret != nil || password.EncodedHash != "" return nil } diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index 3d3693aad..4c68711a0 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -380,7 +380,7 @@ func (u *UserView) setPasswordData(event *models.Event) error { logging.Log("MODEL-sdw4r").WithError(err).Error("could not unmarshal event data") return errors.ThrowInternal(nil, "MODEL-6jhsw", "could not unmarshal data") } - u.PasswordSet = password.Secret != nil + u.PasswordSet = password.Secret != nil || password.EncodedHash != "" u.PasswordInitRequired = !u.PasswordSet u.PasswordChangeRequired = password.ChangeRequired u.PasswordChanged = event.CreationDate diff --git a/openapi/handler.go b/openapi/handler.go index db827128b..b44129018 100644 --- a/openapi/handler.go +++ b/openapi/handler.go @@ -1,24 +1,21 @@ package openapi import ( + "embed" "net/http" - "github.com/rakyll/statik/fs" "github.com/rs/cors" - - _ "github.com/zitadel/zitadel/openapi/statik" ) const ( HandlerPrefix = "/openapi/v2/swagger" ) +//go:embed v2/zitadel/* +var openapi embed.FS + func Start() (http.Handler, error) { - statikFS, err := fs.NewWithNamespace("swagger") - if err != nil { - return nil, err - } handler := &http.ServeMux{} - handler.Handle("/", cors.AllowAll().Handler(http.FileServer(statikFS))) + handler.Handle("/", cors.AllowAll().Handler(http.FileServer(http.FS(openapi)))) return handler, nil } diff --git a/openapi/statik/generate.go b/openapi/statik/generate.go deleted file mode 100644 index 44dcfb50a..000000000 --- a/openapi/statik/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package statik - -//go:generate statik -src=../v2/zitadel -dest=.. -ns=swagger diff --git a/pkg/grpc/protoc/v2/options.pb.go b/pkg/grpc/protoc/v2/options.pb.go new file mode 100644 index 000000000..5b0cd2ff3 --- /dev/null +++ b/pkg/grpc/protoc/v2/options.pb.go @@ -0,0 +1,333 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc (unknown) +// source: zitadel/protoc_gen_zitadel/v2/options.proto + +package protoc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Options struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuthOption *AuthOption `protobuf:"bytes,1,opt,name=auth_option,json=authOption,proto3" json:"auth_option,omitempty"` + HttpResponse *CustomHTTPResponse `protobuf:"bytes,2,opt,name=http_response,json=httpResponse,proto3" json:"http_response,omitempty"` +} + +func (x *Options) Reset() { + *x = Options{} + if protoimpl.UnsafeEnabled { + mi := &file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Options) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Options) ProtoMessage() {} + +func (x *Options) ProtoReflect() protoreflect.Message { + mi := &file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Options.ProtoReflect.Descriptor instead. +func (*Options) Descriptor() ([]byte, []int) { + return file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescGZIP(), []int{0} +} + +func (x *Options) GetAuthOption() *AuthOption { + if x != nil { + return x.AuthOption + } + return nil +} + +func (x *Options) GetHttpResponse() *CustomHTTPResponse { + if x != nil { + return x.HttpResponse + } + return nil +} + +type AuthOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Permission string `protobuf:"bytes,1,opt,name=permission,proto3" json:"permission,omitempty"` + OrgField string `protobuf:"bytes,3,opt,name=org_field,json=orgField,proto3" json:"org_field,omitempty"` +} + +func (x *AuthOption) Reset() { + *x = AuthOption{} + if protoimpl.UnsafeEnabled { + mi := &file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuthOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthOption) ProtoMessage() {} + +func (x *AuthOption) ProtoReflect() protoreflect.Message { + mi := &file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthOption.ProtoReflect.Descriptor instead. +func (*AuthOption) Descriptor() ([]byte, []int) { + return file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescGZIP(), []int{1} +} + +func (x *AuthOption) GetPermission() string { + if x != nil { + return x.Permission + } + return "" +} + +func (x *AuthOption) GetOrgField() string { + if x != nil { + return x.OrgField + } + return "" +} + +type CustomHTTPResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SuccessCode int32 `protobuf:"varint,1,opt,name=success_code,json=successCode,proto3" json:"success_code,omitempty"` +} + +func (x *CustomHTTPResponse) Reset() { + *x = CustomHTTPResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CustomHTTPResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CustomHTTPResponse) ProtoMessage() {} + +func (x *CustomHTTPResponse) ProtoReflect() protoreflect.Message { + mi := &file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CustomHTTPResponse.ProtoReflect.Descriptor instead. +func (*CustomHTTPResponse) Descriptor() ([]byte, []int) { + return file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescGZIP(), []int{2} +} + +func (x *CustomHTTPResponse) GetSuccessCode() int32 { + if x != nil { + return x.SuccessCode + } + return 0 +} + +var file_zitadel_protoc_gen_zitadel_v2_options_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.MethodOptions)(nil), + ExtensionType: (*Options)(nil), + Field: 50001, + Name: "zitadel.protoc_gen_zitadel.v2.options", + Tag: "bytes,50001,opt,name=options", + Filename: "zitadel/protoc_gen_zitadel/v2/options.proto", + }, +} + +// Extension fields to descriptorpb.MethodOptions. +var ( + // optional zitadel.protoc_gen_zitadel.v2.Options options = 50001; + E_Options = &file_zitadel_protoc_gen_zitadel_v2_options_proto_extTypes[0] +) + +var File_zitadel_protoc_gen_zitadel_v2_options_proto protoreflect.FileDescriptor + +var file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDesc = []byte{ + 0x0a, 0x2b, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x32, 0x2f, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, + 0x6e, 0x5f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x32, 0x1a, 0x20, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xad, + 0x01, 0x0a, 0x07, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4a, 0x0a, 0x0b, 0x61, 0x75, + 0x74, 0x68, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x32, 0x2e, + 0x41, 0x75, 0x74, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x0d, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, + 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x52, 0x0c, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, + 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, + 0x6f, 0x72, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6f, 0x72, 0x67, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, + 0x37, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x3a, 0x62, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0xd1, 0x86, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, + 0x5f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x36, 0x5a, 0x34, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, + 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2f, 0x76, 0x32, 0x3b, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescOnce sync.Once + file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescData = file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDesc +) + +func file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescGZIP() []byte { + file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescOnce.Do(func() { + file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescData = protoimpl.X.CompressGZIP(file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescData) + }) + return file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescData +} + +var file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_zitadel_protoc_gen_zitadel_v2_options_proto_goTypes = []interface{}{ + (*Options)(nil), // 0: zitadel.protoc_gen_zitadel.v2.Options + (*AuthOption)(nil), // 1: zitadel.protoc_gen_zitadel.v2.AuthOption + (*CustomHTTPResponse)(nil), // 2: zitadel.protoc_gen_zitadel.v2.CustomHTTPResponse + (*descriptorpb.MethodOptions)(nil), // 3: google.protobuf.MethodOptions +} +var file_zitadel_protoc_gen_zitadel_v2_options_proto_depIdxs = []int32{ + 1, // 0: zitadel.protoc_gen_zitadel.v2.Options.auth_option:type_name -> zitadel.protoc_gen_zitadel.v2.AuthOption + 2, // 1: zitadel.protoc_gen_zitadel.v2.Options.http_response:type_name -> zitadel.protoc_gen_zitadel.v2.CustomHTTPResponse + 3, // 2: zitadel.protoc_gen_zitadel.v2.options:extendee -> google.protobuf.MethodOptions + 0, // 3: zitadel.protoc_gen_zitadel.v2.options:type_name -> zitadel.protoc_gen_zitadel.v2.Options + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 3, // [3:4] is the sub-list for extension type_name + 2, // [2:3] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_zitadel_protoc_gen_zitadel_v2_options_proto_init() } +func file_zitadel_protoc_gen_zitadel_v2_options_proto_init() { + if File_zitadel_protoc_gen_zitadel_v2_options_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Options); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuthOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CustomHTTPResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 1, + NumServices: 0, + }, + GoTypes: file_zitadel_protoc_gen_zitadel_v2_options_proto_goTypes, + DependencyIndexes: file_zitadel_protoc_gen_zitadel_v2_options_proto_depIdxs, + MessageInfos: file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes, + ExtensionInfos: file_zitadel_protoc_gen_zitadel_v2_options_proto_extTypes, + }.Build() + File_zitadel_protoc_gen_zitadel_v2_options_proto = out.File + file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDesc = nil + file_zitadel_protoc_gen_zitadel_v2_options_proto_goTypes = nil + file_zitadel_protoc_gen_zitadel_v2_options_proto_depIdxs = nil +} diff --git a/proto/buf.yaml b/proto/buf.yaml index 6069b76c7..483af8667 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -10,3 +10,28 @@ breaking: lint: use: - MINIMAL + ignore: + - zitadel/action.proto + - zitadel/admin.proto + - zitadel/app.proto + - zitadel/auth_n_key.proto + - zitadel/auth.proto + - zitadel/change.proto + - zitadel/event.proto + - zitadel/idp.proto + - zitadel/instance.proto + - zitadel/management.proto + - zitadel/member.proto + - zitadel/message.proto + - zitadel/metadata.proto + - zitadel/object.proto + - zitadel/options.proto + - zitadel/org.proto + - zitadel/policy.proto + - zitadel/project.proto + - zitadel/quota.proto + - zitadel/settings.proto + - zitadel/system.proto + - zitadel/text.proto + - zitadel/user.proto + - zitadel/v1.proto \ No newline at end of file diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index e50d3afb3..d59882770 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -5866,6 +5866,11 @@ message UpdateLoginPolicyRequest { description: "defines if the user can additionally (to the login name) be identified by their verified phone number" } ]; + bool force_mfa_local_only = 17 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "if activated, only local authenticated users are forced to use MFA. Authentication through IDPs won't prompt a MFA step in the login." + } + ]; } message UpdateLoginPolicyResponse { diff --git a/proto/zitadel/auth.proto b/proto/zitadel/auth.proto index a8e0b38d2..2e291e13c 100644 --- a/proto/zitadel/auth.proto +++ b/proto/zitadel/auth.proto @@ -361,7 +361,7 @@ service AuthService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { tags: "User Profile"; summary: "Get My Profile"; - description: "Returns the profile information of the authenticated user, this includes first name, last name, etc." + description: "Returns the profile information of the authenticated user, this includes given name, family name, etc." }; } @@ -378,7 +378,7 @@ service AuthService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { tags: "User Profile"; summary: "Update My Profile"; - description: "Change the profile information of the authenticated user. This includes information like first name, last name, language, etc." + description: "Change the profile information of the authenticated user. This includes information like given name, family name, language, etc." }; } @@ -820,7 +820,7 @@ service AuthService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { tags: "User Authorizations/Grants" - summary: "List My Authorizations/Grants"; + summary: "List My Organizations"; description: "Returns a list of the organizations where the authenticated user has any authorizations/user grants. The request is made in the context of the requested project. This request can be used in multi-tenancy applications to show the user a tenant switcher." }; } @@ -852,7 +852,7 @@ service AuthService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { tags: "User Authorizations/Grants" - summary: "List My Project Permissions"; + summary: "List My Project Roles"; description: "Returns a list of roles for the authenticated user and for the requesting project (based on the token)." }; } @@ -869,8 +869,8 @@ service AuthService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { tags: "User Memberships" - summary: "List My ZITADEL Permissions"; - description: "Show all the permissions my user has in ZITADEL (ZITADEL Manager)." + summary: "List My ZITADEL Manager Roles"; + description: "Show all the management roles my user has in ZITADEL (ZITADEL Manager)." }; } diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto index b0d5bc97f..4f434e6fe 100644 --- a/proto/zitadel/management.proto +++ b/proto/zitadel/management.proto @@ -1629,7 +1629,7 @@ service ManagementService { }; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - summary: "Create Key for machine user"; + summary: "Delete Key for machine user"; description: "Delete a specific key from a user. The user will not be able to authenticate with that key afterward." tags: "Users"; tags: "User Machine"; @@ -7406,8 +7406,14 @@ message ImportHumanUserRequest { description: "Use this to import hashed passwords from another system." } }; - string value = 1; - string algorithm = 2; + string value = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"$2y$12$hXUrnqdq1RIIYZ2HPytIIe5lXdIvbhqrTvdPsSF7o.jFh817Z6lwm\""; + description: "Encoded hash of a password in Modular Crypt Format: https://passlib.readthedocs.io/en/stable/modular_crypt_format.html" + } + ]; + reserved 2; // was algortithm, which is actually obtained from the encoded hash + reserved "algortithm"; } message IDP { string config_id = 1 [ @@ -8935,8 +8941,8 @@ message AddOIDCAppRequest { ]; repeated string additional_origins = 16 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "[\"https://console.zitadel.ch/auth/callback\"]"; - description: "Additional origins (other than the redirect_uris) from where the API can be used"; + example: "[\"scheme://localhost:8080\"]"; + description: "Additional origins (other than the redirect_uris) from where the API can be used, provided string has to be an origin (scheme://hostname[:port]) without path, query or fragment"; } ]; bool skip_native_app_success_page = 17 [ @@ -9110,8 +9116,8 @@ message UpdateOIDCAppConfigRequest { ]; repeated string additional_origins = 15 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "[\"https://console.zitadel.ch/auth/callback\"]"; - description: "Additional origins (other than the redirect_uris) from where the API can be used"; + example: "[\"scheme://localhost:8080\"]"; + description: "Additional origins (other than the redirect_uris) from where the API can be used, provided string has to be an origin (scheme://hostname[:port]) without path, query or fragment"; } ]; bool skip_native_app_success_page = 16 [ @@ -9648,6 +9654,11 @@ message AddCustomLoginPolicyRequest { description: "defines if the user can additionally (to the login name) be identified by their verified phone number" } ]; + bool force_mfa_local_only = 20 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "if activated, only local authenticated users are forced to use MFA. Authentication through IDPs won't prompt a MFA step in the login." + } + ]; } message AddCustomLoginPolicyResponse { @@ -9692,6 +9703,11 @@ message UpdateCustomLoginPolicyRequest { description: "defines if the user can additionally (to the login name) be identified by their verified phone number" } ]; + bool force_mfa_local_only = 17 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "if activated, only local authenticated users are forced to use MFA. Authentication through IDPs won't prompt a MFA step in the login." + } + ]; } message UpdateCustomLoginPolicyResponse { diff --git a/proto/zitadel/oidc/v2alpha/authorization.proto b/proto/zitadel/oidc/v2alpha/authorization.proto new file mode 100644 index 000000000..69a14a3d0 --- /dev/null +++ b/proto/zitadel/oidc/v2alpha/authorization.proto @@ -0,0 +1,117 @@ +syntax = "proto3"; + +package zitadel.oidc.v2alpha; + +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; + +option go_package = "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha;oidc"; + +message AuthRequest{ + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + external_docs: { + url: "https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest"; + description: "Find out more about OIDC Auth Request parameters"; + } + }; + + string id = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "ID of the authorization request"; + } + ]; + + google.protobuf.Timestamp creation_date = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Time when the auth request was created"; + } + ]; + + string client_id = 3 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "OIDC client ID of the application that created the auth request"; + } + ]; + + repeated string scope = 4 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Requested scopes by the application, which the user must consent to."; + } + ]; + + string redirect_uri = 5 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Base URI that points back to the application"; + } + ]; + + repeated Prompt prompt = 6 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Prompts that must be displayed to the user"; + } + ]; + + repeated string ui_locales = 7 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "End-User's preferred languages and scripts for the user interface, represented as a list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value [fr-CA, fr, en] represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported."; + } + ]; + + optional string login_hint = 8 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Login hint can be set by the application with a user identifier such as an email or phone number."; + } + ]; + + optional google.protobuf.Duration max_age = 9 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Specifies the allowable elapsed time in seconds since the last time the End-User was actively authenticated. If the elapsed time is greater than this value, or the field is present with 0 duration, the user must be re-authenticated."; + } + ]; + + optional string hint_user_id = 10 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "User ID taken from a ID Token Hint if it was present and valid."; + } + ]; +} + +enum Prompt { + PROMPT_UNSPECIFIED = 0; + PROMPT_NONE = 1; + PROMPT_LOGIN = 2; + PROMPT_CONSENT = 3; + PROMPT_SELECT_ACCOUNT = 4; + PROMPT_CREATE = 5; +} + +message AuthorizationError { + ErrorReason error = 1; + optional string error_description = 2; + optional string error_uri = 3; +} + +enum ErrorReason { + ERROR_REASON_UNSPECIFIED = 0; + + // Error states from https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1 + ERROR_REASON_INVALID_REQUEST = 1; + ERROR_REASON_UNAUTHORIZED_CLIENT = 2; + ERROR_REASON_ACCESS_DENIED = 3; + ERROR_REASON_UNSUPPORTED_RESPONSE_TYPE = 4; + ERROR_REASON_INVALID_SCOPE = 5; + ERROR_REASON_SERVER_ERROR = 6; + ERROR_REASON_TEMPORARY_UNAVAILABLE = 7; + + // Error states from https://openid.net/specs/openid-connect-core-1_0.html#AuthError + ERROR_REASON_INTERACTION_REQUIRED = 8; + ERROR_REASON_LOGIN_REQUIRED = 9; + ERROR_REASON_ACCOUNT_SELECTION_REQUIRED = 10; + ERROR_REASON_CONSENT_REQUIRED = 11; + ERROR_REASON_INVALID_REQUEST_URI = 12; + ERROR_REASON_INVALID_REQUEST_OBJECT = 13; + ERROR_REASON_REQUEST_NOT_SUPPORTED = 14; + ERROR_REASON_REQUEST_URI_NOT_SUPPORTED = 15; + ERROR_REASON_REGISTRATION_NOT_SUPPORTED = 16; +} \ No newline at end of file diff --git a/proto/zitadel/oidc/v2alpha/oidc_service.proto b/proto/zitadel/oidc/v2alpha/oidc_service.proto new file mode 100644 index 000000000..94ba36413 --- /dev/null +++ b/proto/zitadel/oidc/v2alpha/oidc_service.proto @@ -0,0 +1,190 @@ +syntax = "proto3"; + +package zitadel.oidc.v2alpha; + +import "zitadel/object/v2alpha/object.proto"; +import "zitadel/protoc_gen_zitadel/v2/options.proto"; +import "zitadel/oidc/v2alpha/authorization.proto"; +import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; +import "validate/validate.proto"; + +option go_package = "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha;oidc"; + +option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { + info: { + title: "OIDC Service"; + version: "2.0-alpha"; + description: "Get OIDC Auth Request details and create callback URLs. This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login."; + contact:{ + name: "ZITADEL" + url: "https://zitadel.com" + email: "hi@zitadel.com" + } + license: { + name: "Apache 2.0", + url: "https://github.com/zitadel/zitadel/blob/main/LICENSE"; + }; + }; + schemes: HTTPS; + schemes: HTTP; + + consumes: "application/json"; + consumes: "application/grpc"; + + produces: "application/json"; + produces: "application/grpc"; + + consumes: "application/grpc-web+proto"; + produces: "application/grpc-web+proto"; + + host: "$ZITADEL_DOMAIN"; + base_path: "/"; + + external_docs: { + description: "Detailed information about ZITADEL", + url: "https://zitadel.com/docs" + } + + responses: { + key: "403"; + value: { + description: "Returned when the user does not have permission to access the resource."; + schema: { + json_schema: { + ref: "#/definitions/rpcStatus"; + } + } + } + } + responses: { + key: "404"; + value: { + description: "Returned when the resource does not exist."; + schema: { + json_schema: { + ref: "#/definitions/rpcStatus"; + } + } + } + } +}; + +service OIDCService { + rpc GetAuthRequest (GetAuthRequestRequest) returns (GetAuthRequestResponse) { + option (google.api.http) = { + get: "/v2alpha/oidc/auth_requests/{auth_request_id}" + }; + + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "authenticated" + } + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get OIDC Auth Request details"; + description: "Get OIDC Auth Request details by ID, obtained from the redirect URL. Returns details that are parsed from the application's Auth Request." + responses: { + key: "200" + value: { + description: "OK"; + } + }; + }; + } + + rpc CreateCallback (CreateCallbackRequest) returns (CreateCallbackResponse) { + option (google.api.http) = { + post: "/v2alpha/oidc/auth_requests/{auth_request_id}" + body: "*" + }; + + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "authenticated" + } + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Finalize an Auth Request and get the callback URL."; + description: "Finalize an Auth Request and get the callback URL for success or failure. The user must be redirected to the URL in order to inform the application about the success or failure. On success, the URL contains details for the application to obtain the tokens. This method can only be called once for an Auth request." + responses: { + key: "200" + value: { + description: "OK"; + } + }; + }; + } +} + +message GetAuthRequestRequest { + string auth_request_id = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + description: "ID of the Auth Request, as obtained from the redirect URL."; + example: "\"163840776835432705\""; + } + ]; +} + +message GetAuthRequestResponse { + AuthRequest auth_request = 1; +} + +message CreateCallbackRequest { + string auth_request_id = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Set this field when the authorization flow failed. It creates a callback URL to the application, with the error details set."; + ref: "https://openid.net/specs/openid-connect-core-1_0.html#AuthError"; + } + ]; + + oneof callback_kind { + option (validate.required) = true; + Session session = 2; + AuthorizationError error = 3 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Set this field when the authorization flow failed. It creates a callback URL to the application, with the error details set."; + ref: "https://openid.net/specs/openid-connect-core-1_0.html#AuthError"; + } + ]; + } +} + +message Session { + string session_id = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + description: "ID of the session, used to login the user. Connects the session to the Auth Request."; + example: "\"163840776835432705\""; + } + ]; + + string session_token = 2 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + description: "Token to verify the session is valid"; + } + ]; +} + +message CreateCallbackResponse { + zitadel.object.v2alpha.Details details = 1; + string callback_url = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Callback URL where the user should be redirected, using a \"302 FOUND\" status. Contains details for the application to obtain the tokens on success, or error details on failure. Note that this field must be treated as credentials, as the contained code can be used to obtain tokens on behalve of the user."; + example: "\"https://client.example.org/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj\"" + } + ]; +} + diff --git a/proto/zitadel/options.proto b/proto/zitadel/options.proto index b71082858..e3dc45f2a 100644 --- a/proto/zitadel/options.proto +++ b/proto/zitadel/options.proto @@ -6,7 +6,6 @@ import "google/protobuf/descriptor.proto"; option go_package = "github.com/zitadel/zitadel/internal/protoc/protoc-gen-authoption/authoption"; - extend google.protobuf.MethodOptions { AuthOption auth_option = 50000; } diff --git a/proto/zitadel/policy.proto b/proto/zitadel/policy.proto index c6cbc7a46..49dbe34dc 100644 --- a/proto/zitadel/policy.proto +++ b/proto/zitadel/policy.proto @@ -239,6 +239,11 @@ message LoginPolicy { description: "defines if the user can additionally (to the login name) be identified by their verified phone number" } ]; + bool force_mfa_local_only = 22 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "if activated, only local authenticated users are forced to use MFA. Authentication through IDPs won't prompt a MFA step in the login." + } + ]; } enum SecondFactorType { diff --git a/proto/zitadel/session/v2alpha/session.proto b/proto/zitadel/session/v2alpha/session.proto index b3e11a443..e6e69ca50 100644 --- a/proto/zitadel/session/v2alpha/session.proto +++ b/proto/zitadel/session/v2alpha/session.proto @@ -74,6 +74,11 @@ message UserFactor { description: "\"display name of the checked user\""; } ]; + string organisation_id = 5 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "\"organisation id of the checked user\""; + } + ]; } message PasswordFactor { diff --git a/proto/zitadel/settings/v2alpha/login_settings.proto b/proto/zitadel/settings/v2alpha/login_settings.proto index d84423c3c..9d4b37237 100644 --- a/proto/zitadel/settings/v2alpha/login_settings.proto +++ b/proto/zitadel/settings/v2alpha/login_settings.proto @@ -104,6 +104,11 @@ message LoginSettings { description: "resource_owner_type returns if the settings is managed on the organization or on the instance"; } ]; + bool force_mfa_local_only = 22 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "if activated, only local authenticated users are forced to use MFA. Authentication through IDPs won't prompt a MFA step in the login." + } + ]; } enum SecondFactorType { diff --git a/proto/zitadel/user/v2alpha/password.proto b/proto/zitadel/user/v2alpha/password.proto index 38089b0b0..cb5415b12 100644 --- a/proto/zitadel/user/v2alpha/password.proto +++ b/proto/zitadel/user/v2alpha/password.proto @@ -32,17 +32,7 @@ message HashedPassword { max_length: 200; } ]; - string algorithm = 2 [ - (validate.rules).string = {min_len: 1, max_len: 200, const: "bcrypt"}, - (google.api.field_behavior) = REQUIRED, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"bcrypt\""; - description: "\"algorithm used for the hash. currently only bcrypt is supported\""; - min_length: 1, - max_length: 200; - } - ]; - bool change_required = 3; + bool change_required = 2; } message SendPasswordResetLink { diff --git a/proto/zitadel/user/v2alpha/user_service.proto b/proto/zitadel/user/v2alpha/user_service.proto index 1534a4d74..50562bcf5 100644 --- a/proto/zitadel/user/v2alpha/user_service.proto +++ b/proto/zitadel/user/v2alpha/user_service.proto @@ -430,8 +430,8 @@ service UserService { }; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - summary: "Request a code to reset a password"; - description: "Request a code to reset a password"; + summary: "Change password"; + description: "Change the password of a user with either a verification code or the current password."; responses: { key: "200" value: { @@ -574,7 +574,7 @@ message RegisterPasskeyRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; optional PasskeyRegistrationCode code = 2 [ @@ -598,7 +598,7 @@ message RegisterPasskeyResponse{ zitadel.object.v2alpha.Details details = 1; string passkey_id = 2 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\"" + example: "\"163840776835432705\"" } ]; google.protobuf.Struct public_key_credential_creation_options = 3 [ @@ -616,7 +616,7 @@ message VerifyPasskeyRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string passkey_id = 2 [ @@ -625,7 +625,7 @@ message VerifyPasskeyRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\""; + example: "\"163840776835432705\""; } ]; google.protobuf.Struct public_key_credential = 3 [ @@ -660,7 +660,7 @@ message RegisterU2FRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string domain = 2 [ @@ -674,7 +674,7 @@ message RegisterU2FResponse{ zitadel.object.v2alpha.Details details = 1; string u2f_id = 2 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\"" + example: "\"163840776835432705\"" } ]; google.protobuf.Struct public_key_credential_creation_options = 3 [ @@ -692,7 +692,7 @@ message VerifyU2FRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string u2f_id = 2 [ @@ -701,7 +701,7 @@ message VerifyU2FRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\""; + example: "\"163840776835432705\""; } ]; google.protobuf.Struct public_key_credential = 3 [ @@ -736,7 +736,7 @@ message RegisterTOTPRequest { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; } @@ -762,7 +762,7 @@ message VerifyTOTPRegistrationRequest { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string code = 2 [ @@ -786,7 +786,7 @@ message CreatePasskeyRegistrationLinkRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; // if no medium is specified, an email is sent with the default url @@ -813,7 +813,7 @@ message StartIdentityProviderFlowRequest{ description: "ID for existing identity provider" min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string success_url = 2 [ @@ -855,7 +855,7 @@ message RetrieveIdentityProviderInformationRequest{ description: "ID of the intent, previously returned on the success response of the IDP callback" min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string token = 2 [ diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index fb57ccd13..000000000 --- a/yarn.lock +++ /dev/null @@ -1,4 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - -