diff --git a/.github/workflows/brew-bump-cli.yml b/.github/workflows/brew-bump-cli.yml index b1eb1708cb..33c6b7c368 100644 --- a/.github/workflows/brew-bump-cli.yml +++ b/.github/workflows/brew-bump-cli.yml @@ -29,7 +29,7 @@ jobs: secrets: "brew-bump-workflow-pat" - name: Update Homebrew formula - uses: dawidd6/action-homebrew-bump-formula@75ed025ff3ad1d617862838b342b06d613a0ddf3 # v3.10.1 + uses: dawidd6/action-homebrew-bump-formula@baf2b60c51fc1f8453c884b0c61052668a71bd1d # v3.11.0 with: # Required, custom GitHub access token with the 'public_repo' and 'workflow' scopes token: ${{ steps.retrieve-secrets.outputs.brew-bump-workflow-pat }} diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index 75bce90bb2..585a888ae1 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -371,7 +371,7 @@ jobs: secrets: "crowdin-api-token" - name: Upload Sources - uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0 + uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index 87c34da588..2c3ea3982a 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -297,7 +297,7 @@ jobs: echo "BW Package Version: $_PACKAGE_VERSION" - name: Get bw linux cli - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: bw-linux-${{ env._PACKAGE_VERSION }}.zip path: apps/cli/dist/snap diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index 2823e7732c..354fd4edda 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -167,7 +167,7 @@ jobs: working-directory: ./ - name: Cache Native Module - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 id: cache with: path: | @@ -296,7 +296,7 @@ jobs: working-directory: ./ - name: Cache Native Module - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 id: cache with: path: apps/desktop/desktop_native/*.node @@ -476,14 +476,14 @@ jobs: - name: Cache Build id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Cache Safari id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -576,7 +576,7 @@ jobs: working-directory: ./ - name: Cache Native Module - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 id: cache with: path: apps/desktop/desktop_native/*.node @@ -637,14 +637,14 @@ jobs: - name: Get Build Cache id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Setup Safari Cache id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -737,7 +737,7 @@ jobs: working-directory: ./ - name: Cache Native Module - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 id: cache with: path: apps/desktop/desktop_native/*.node @@ -753,7 +753,7 @@ jobs: run: npm run build - name: Download Browser artifact - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: path: ${{ github.workspace }}/browser-build-artifacts @@ -843,14 +843,14 @@ jobs: - name: Get Build Cache id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Setup Safari Cache id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -943,7 +943,7 @@ jobs: working-directory: ./ - name: Cache Native Module - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 id: cache with: path: apps/desktop/desktop_native/*.node @@ -959,7 +959,7 @@ jobs: run: npm run build - name: Download Browser artifact - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: path: ${{ github.workspace }}/browser-build-artifacts @@ -1036,14 +1036,14 @@ jobs: - name: Get Build Cache id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Setup Safari Cache id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -1136,7 +1136,7 @@ jobs: working-directory: ./ - name: Cache Native Module - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 id: cache with: path: apps/desktop/desktop_native/*.node @@ -1152,7 +1152,7 @@ jobs: run: npm run build - name: Download Browser artifact - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: path: ${{ github.workspace }}/browser-build-artifacts @@ -1211,7 +1211,7 @@ jobs: secrets: "crowdin-api-token" - name: Upload Sources - uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0 + uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 0a1ab23651..abd2538773 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -194,7 +194,7 @@ jobs: secrets: "github-pat-bitwarden-devops-bot-repo-scope" - name: Download ${{ matrix.artifact_name }} artifact - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip path: apps/web @@ -270,7 +270,7 @@ jobs: secrets: "crowdin-api-token" - name: Upload Sources - uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0 + uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 41aaf55826..ab08d509b3 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -33,7 +33,7 @@ jobs: - name: Cache npm id: npm-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: "~/.npm" key: ${{ runner.os }}-npm-chromatic-${{ hashFiles('**/package-lock.json') }} @@ -46,7 +46,7 @@ jobs: run: npm run build-storybook:ci - name: Publish to Chromatic - uses: chromaui/action@76bda3648003815314bd50adaa553ee612a7f36c # v10.9.2 + uses: chromaui/action@c9067691aca4a28d6fbb40d9eea6e144369fbcae # v10.9.5 with: token: ${{ secrets.GITHUB_TOKEN }} projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index aacef42b82..2d784652a5 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -19,14 +19,14 @@ on: description: "Branch or Tag name to deploy (examples: 'main', 'feature/sm', 'web-v2023.12.0')" type: string default: main - invert-default-sync-delete-destination-files-value: - description: "Invert the default sync-delete-destination-files value" + force-delete-destination: + description: "Delete remote files that are not found locally" type: boolean default: false debug: description: "Debug mode" type: boolean - default: false + default: true workflow_call: inputs: @@ -38,8 +38,8 @@ on: description: "Branch or Tag name to deploy (examples: 'main', 'feature/sm', 'web-v2023.12.0')" type: string default: main - invert-default-sync-delete-destination-files-value: - description: "Invert the default sync-delete-destination-files value" + force-delete-destination: + description: "Delete remote files that are not found locally" type: boolean default: false debug: @@ -71,14 +71,6 @@ jobs: echo "configuring the Web deploy for ${{ inputs.environment }}" echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT - # Invert the default value for sync-delete-destination-files - if [ ${{ inputs.invert-default-sync-delete-destination-files-value }} ]; then - echo "sync-delete-destination-files=true" >> $GITHUB_OUTPUT - else - # This is the default value for USQA, EUQA, USPROD, and EUPROD - echo "sync-delete-destination-files=false" >> $GITHUB_OUTPUT - fi - case ${{ inputs.environment }} in "USQA") echo "azure-login-creds=AZURE_KV_US_QA_SERVICE_PRINCIPAL" >> $GITHUB_OUTPUT @@ -114,13 +106,6 @@ jobs: echo "environment-artifact=web-*-cloud-usdev.zip" >> $GITHUB_OUTPUT echo "environment-name=Web Vault - US Development Cloud" >> $GITHUB_OUTPUT echo "environment-url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT - - if [ ${{ inputs.invert-default-sync-delete-destination-files-value }} ]; then - echo "sync-delete-destination-files=false" >> $GITHUB_OUTPUT - else - # This is the default value for USDEV - echo "sync-delete-destination-files=true" >> $GITHUB_OUTPUT - fi ;; esac # Set the sync utility to use for deployment to the environment (az-sync or azcopy) @@ -285,7 +270,7 @@ jobs: --source "./build" \ --container '$web' \ --connection-string "${{ steps.retrieve-secrets-az-sync.outputs.sa-bitwarden-web-vault-dev-key-temp }}" \ - --delete-destination=${{ needs.setup.outputs.sync-delete-destination-files }} + --delete-destination=${{ inputs.force-delete-destination }} - name: Sync to Azure Storage Account using azcopy if: ${{ needs.setup.outputs.sync-utility == 'azcopy' }} @@ -297,7 +282,7 @@ jobs: AZCOPY_TENANT_ID: ${{ steps.retrieve-secrets-azcopy.outputs.sp-bitwarden-web-vault-tenant }} run: | azcopy sync ./build 'https://${{ steps.retrieve-secrets-azcopy.outputs.sa-bitwarden-web-vault-name }}.blob.core.windows.net/$web/' \ - --delete-destination=${{ needs.setup.outputs.sync-delete-destination-files }} --compare-hash="MD5" + --delete-destination=${{ inputs.force-delete-destination }} --compare-hash="MD5" - name: Debug sync logs if: ${{ inputs.debug }} @@ -309,7 +294,7 @@ jobs: - name: Update deployment status to Success if: success() - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' environment-url: ${{ env._ENVIRONMENT_URL }} @@ -318,7 +303,7 @@ jobs: - name: Update deployment status to Failure if: failure() - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' environment-url: ${{ env._ENVIRONMENT_URL }} diff --git a/.github/workflows/release-browser.yml b/.github/workflows/release-browser.yml index dc4d5b34d7..c260f19581 100644 --- a/.github/workflows/release-browser.yml +++ b/.github/workflows/release-browser.yml @@ -155,7 +155,7 @@ jobs: - name: Update deployment status to Success if: ${{ success() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'success' @@ -163,7 +163,7 @@ jobs: - name: Update deployment status to Failure if: ${{ failure() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'failure' diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 4c46ffa6b7..add0c539e9 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -118,7 +118,7 @@ jobs: - name: Update deployment status to Success if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'success' @@ -126,7 +126,7 @@ jobs: - name: Update deployment status to Failure if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'failure' diff --git a/.github/workflows/release-desktop-beta.yml b/.github/workflows/release-desktop-beta.yml index d595a49d75..20bffb956e 100644 --- a/.github/workflows/release-desktop-beta.yml +++ b/.github/workflows/release-desktop-beta.yml @@ -424,14 +424,14 @@ jobs: - name: Cache Build id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Cache Safari id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -555,14 +555,14 @@ jobs: - name: Get Build Cache id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Setup Safari Cache id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -659,7 +659,7 @@ jobs: - name: Download artifact from hotfix-rc if: github.ref == 'refs/heads/hotfix-rc' - uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 + uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 with: workflow: build-browser.yml workflow_conclusion: success @@ -668,7 +668,7 @@ jobs: - name: Download artifact from rc if: github.ref == 'refs/heads/rc' - uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 + uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 with: workflow: build-browser.yml workflow_conclusion: success @@ -677,7 +677,7 @@ jobs: - name: Download artifacts from main if: ${{ github.ref != 'refs/heads/rc' && github.ref != 'refs/heads/hotfix-rc' }} - uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 + uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 with: workflow: build-browser.yml workflow_conclusion: success @@ -765,14 +765,14 @@ jobs: - name: Get Build Cache id: build-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/desktop/build key: ${{ runner.os }}-${{ github.run_id }}-build - name: Setup Safari Cache id: safari-cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension @@ -864,7 +864,7 @@ jobs: - name: Download artifact from hotfix-rc if: github.ref == 'refs/heads/hotfix-rc' - uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 + uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 with: workflow: build-browser.yml workflow_conclusion: success @@ -873,7 +873,7 @@ jobs: - name: Download artifact from rc if: github.ref == 'refs/heads/rc' - uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 + uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 with: workflow: build-browser.yml workflow_conclusion: success @@ -882,7 +882,7 @@ jobs: - name: Download artifact from main if: ${{ github.ref != 'refs/heads/rc' && github.ref != 'refs/heads/hotfix-rc' }} - uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0 + uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 with: workflow: build-browser.yml workflow_conclusion: success @@ -953,7 +953,7 @@ jobs: cf-prod-account" - name: Download all artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: path: apps/desktop/artifacts @@ -992,7 +992,7 @@ jobs: - name: Update deployment status to Success if: ${{ success() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'success' @@ -1000,7 +1000,7 @@ jobs: - name: Update deployment status to Failure if: ${{ failure() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'failure' diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index ad6883bfc9..cf857d7177 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -231,7 +231,7 @@ jobs: - name: Update deployment status to Success if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'success' @@ -239,7 +239,7 @@ jobs: - name: Update deployment status to Failure if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' state: 'failure' diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index 42acd62420..3e07f7fc98 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -268,7 +268,7 @@ jobs: - name: Update deployment status to Success if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' environment-url: http://vault.bitwarden.com @@ -277,7 +277,7 @@ jobs: - name: Update deployment status to Failure if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }} - uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' environment-url: http://vault.bitwarden.com diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b3dd6c8da1..3c650d8a62 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: fail-on-error: true - name: Upload to codecov.io - uses: codecov/codecov-action@e0b68c6749509c5f83f984dd99a76a1c1a231044 # v4.0.1 + uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 6b5f1a8297..44decc01a9 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -4,6 +4,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { NOTIFICATION_BAR_LIFESPAN_MS } from "@bitwarden/common/autofill/constants"; import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -19,7 +20,6 @@ import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window"; import { BrowserApi } from "../../platform/browser/browser-api"; import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window"; -import { NOTIFICATION_BAR_LIFESPAN_MS } from "../constants"; import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; import { AutofillService } from "../services/abstractions/autofill.service"; diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index 2820ed6cd1..c19505118b 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -2,6 +2,10 @@ import { mock, mockReset } from "jest-mock-extended"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; +import { + SHOW_AUTOFILL_BUTTON, + AutofillOverlayVisibility, +} from "@bitwarden/common/autofill/constants"; import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { ThemeType } from "@bitwarden/common/platform/enums"; import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service"; @@ -15,7 +19,6 @@ import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; import { BrowserApi } from "../../platform/browser/browser-api"; import BrowserPlatformUtilsService from "../../platform/services/browser-platform-utils.service"; import { BrowserStateService } from "../../platform/services/browser-state.service"; -import { SHOW_AUTOFILL_BUTTON } from "../constants"; import { AutofillService } from "../services/abstractions/autofill.service"; import { createAutofillPageDetailsMock, @@ -28,7 +31,6 @@ import { flushPromises, sendExtensionRuntimeMessage, sendPortMessage } from "../ import { AutofillOverlayElement, AutofillOverlayPort, - AutofillOverlayVisibility, RedirectFocusDirection, } from "../utils/autofill-overlay.enum"; diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 583e22fbe8..49d27391cf 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -3,7 +3,9 @@ import { firstValueFrom } from "rxjs"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { SHOW_AUTOFILL_BUTTON } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -22,13 +24,8 @@ import { openViewVaultItemPopout, openAddEditVaultItemPopout, } from "../../vault/popup/utils/vault-popout-window"; -import { SHOW_AUTOFILL_BUTTON } from "../constants"; import { AutofillService, PageDetail } from "../services/abstractions/autofill.service"; -import { - InlineMenuVisibilitySetting, - AutofillOverlayElement, - AutofillOverlayPort, -} from "../utils/autofill-overlay.enum"; +import { AutofillOverlayElement, AutofillOverlayPort } from "../utils/autofill-overlay.enum"; import { LockedVaultPendingNotificationsData } from "./abstractions/notification.background"; import { diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts index f2312a0d66..e54f37489b 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts @@ -3,14 +3,6 @@ import { mock, MockProxy } from "jest-mock-extended"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; -import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; - import { AUTOFILL_ID, COPY_PASSWORD_ID, @@ -18,7 +10,14 @@ import { COPY_VERIFICATION_CODE_ID, GENERATE_PASSWORD_ID, NOOP_COMMAND_SUFFIX, -} from "../constants"; +} from "@bitwarden/common/autofill/constants"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; +import { CipherType } from "@bitwarden/common/vault/enums"; +import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; +import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CopyToClipboardAction, diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts index 21ff91c02d..760b833044 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts @@ -2,6 +2,20 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { + AUTOFILL_CARD_ID, + AUTOFILL_ID, + AUTOFILL_IDENTITY_ID, + COPY_IDENTIFIER_ID, + COPY_PASSWORD_ID, + COPY_USERNAME_ID, + COPY_VERIFICATION_CODE_ID, + CREATE_CARD_ID, + CREATE_IDENTITY_ID, + CREATE_LOGIN_ID, + GENERATE_PASSWORD_ID, + NOOP_COMMAND_SUFFIX, +} from "@bitwarden/common/autofill/constants"; import { EventType } from "@bitwarden/common/enums"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; @@ -38,20 +52,6 @@ import { LockedVaultPendingNotificationsData } from "../background/abstractions/ import { autofillServiceFactory } from "../background/service_factories/autofill-service.factory"; import { copyToClipboard, GeneratePasswordToClipboardCommand } from "../clipboard"; import { AutofillTabCommand } from "../commands/autofill-tab-command"; -import { - AUTOFILL_CARD_ID, - AUTOFILL_ID, - AUTOFILL_IDENTITY_ID, - COPY_IDENTIFIER_ID, - COPY_PASSWORD_ID, - COPY_USERNAME_ID, - COPY_VERIFICATION_CODE_ID, - CREATE_CARD_ID, - CREATE_IDENTITY_ID, - CREATE_LOGIN_ID, - GENERATE_PASSWORD_ID, - NOOP_COMMAND_SUFFIX, -} from "../constants"; import { AutofillCipherTypeId } from "../types"; export type CopyToClipboardOptions = { text: string; tab: chrome.tabs.Tab }; diff --git a/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts b/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts index 9e115749e8..f2b17d2f08 100644 --- a/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts +++ b/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts @@ -1,5 +1,6 @@ import { mock, MockProxy } from "jest-mock-extended"; +import { NOOP_COMMAND_SUFFIX } from "@bitwarden/common/autofill/constants"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { CipherType } from "@bitwarden/common/vault/enums"; @@ -7,7 +8,6 @@ import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; -import { NOOP_COMMAND_SUFFIX } from "../constants"; import { MainContextMenuHandler } from "./main-context-menu-handler"; diff --git a/apps/browser/src/autofill/browser/main-context-menu-handler.ts b/apps/browser/src/autofill/browser/main-context-menu-handler.ts index 0051c69154..19154fbfb8 100644 --- a/apps/browser/src/autofill/browser/main-context-menu-handler.ts +++ b/apps/browser/src/autofill/browser/main-context-menu-handler.ts @@ -1,3 +1,19 @@ +import { + AUTOFILL_CARD_ID, + AUTOFILL_ID, + AUTOFILL_IDENTITY_ID, + COPY_IDENTIFIER_ID, + COPY_PASSWORD_ID, + COPY_USERNAME_ID, + COPY_VERIFICATION_CODE_ID, + CREATE_CARD_ID, + CREATE_IDENTITY_ID, + CREATE_LOGIN_ID, + GENERATE_PASSWORD_ID, + NOOP_COMMAND_SUFFIX, + ROOT_ID, + SEPARATOR_ID, +} from "@bitwarden/common/autofill/constants"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; @@ -21,22 +37,6 @@ import { StateServiceInitOptions, } from "../../platform/background/service-factories/state-service.factory"; import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; -import { - AUTOFILL_CARD_ID, - AUTOFILL_ID, - AUTOFILL_IDENTITY_ID, - COPY_IDENTIFIER_ID, - COPY_PASSWORD_ID, - COPY_USERNAME_ID, - COPY_VERIFICATION_CODE_ID, - CREATE_CARD_ID, - CREATE_IDENTITY_ID, - CREATE_LOGIN_ID, - GENERATE_PASSWORD_ID, - NOOP_COMMAND_SUFFIX, - ROOT_ID, - SEPARATOR_ID, -} from "../constants"; import { InitContextMenuItems } from "./abstractions/main-context-menu-handler"; diff --git a/apps/browser/src/autofill/content/autofill-init.spec.ts b/apps/browser/src/autofill/content/autofill-init.spec.ts index 65854c463e..8912a8c0ba 100644 --- a/apps/browser/src/autofill/content/autofill-init.spec.ts +++ b/apps/browser/src/autofill/content/autofill-init.spec.ts @@ -1,12 +1,13 @@ import { mock } from "jest-mock-extended"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import AutofillPageDetails from "../models/autofill-page-details"; import AutofillScript from "../models/autofill-script"; import AutofillOverlayContentService from "../services/autofill-overlay-content.service"; import { flushPromises, sendExtensionRuntimeMessage } from "../spec/testing-utils"; -import { AutofillOverlayVisibility, RedirectFocusDirection } from "../utils/autofill-overlay.enum"; +import { RedirectFocusDirection } from "../utils/autofill-overlay.enum"; import { AutofillExtensionMessage } from "./abstractions/autofill-init"; import AutofillInit from "./autofill-init"; diff --git a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts index 5ab7988157..a7c11ea472 100644 --- a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts +++ b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts @@ -1,8 +1,8 @@ import { mock } from "jest-mock-extended"; +import { EVENTS } from "@bitwarden/common/autofill/constants"; import { ThemeType } from "@bitwarden/common/platform/enums"; -import { EVENTS } from "../../constants"; import { createPortSpyMock } from "../../spec/autofill-mocks"; import { flushPromises, diff --git a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts index 4512070ff7..0ec7db131c 100644 --- a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts +++ b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts @@ -1,6 +1,6 @@ +import { EVENTS } from "@bitwarden/common/autofill/constants"; import { ThemeType } from "@bitwarden/common/platform/enums"; -import { EVENTS } from "../../constants"; import { setElementStyles } from "../../utils"; import { BackgroundPortMessageHandlers, diff --git a/apps/browser/src/autofill/overlay/pages/button/autofill-overlay-button.ts b/apps/browser/src/autofill/overlay/pages/button/autofill-overlay-button.ts index 12c4f2540f..0d68b37e2f 100644 --- a/apps/browser/src/autofill/overlay/pages/button/autofill-overlay-button.ts +++ b/apps/browser/src/autofill/overlay/pages/button/autofill-overlay-button.ts @@ -1,8 +1,8 @@ import "@webcomponents/custom-elements"; import "lit/polyfill-support.js"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { EVENTS } from "@bitwarden/common/autofill/constants"; -import { EVENTS } from "../../../constants"; import { buildSvgDomElement } from "../../../utils"; import { logoIcon, logoLockedIcon } from "../../../utils/svg-icons"; import { diff --git a/apps/browser/src/autofill/overlay/pages/list/autofill-overlay-list.ts b/apps/browser/src/autofill/overlay/pages/list/autofill-overlay-list.ts index 6feb31533e..305a230e5c 100644 --- a/apps/browser/src/autofill/overlay/pages/list/autofill-overlay-list.ts +++ b/apps/browser/src/autofill/overlay/pages/list/autofill-overlay-list.ts @@ -1,9 +1,9 @@ import "@webcomponents/custom-elements"; import "lit/polyfill-support.js"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { EVENTS } from "@bitwarden/common/autofill/constants"; import { OverlayCipherData } from "../../../background/abstractions/overlay.background"; -import { EVENTS } from "../../../constants"; import { buildSvgDomElement } from "../../../utils"; import { globeIcon, lockIcon, plusIcon, viewCipherIcon } from "../../../utils/svg-icons"; import { diff --git a/apps/browser/src/autofill/overlay/pages/shared/autofill-overlay-page-element.ts b/apps/browser/src/autofill/overlay/pages/shared/autofill-overlay-page-element.ts index d556e5d52a..34f115f401 100644 --- a/apps/browser/src/autofill/overlay/pages/shared/autofill-overlay-page-element.ts +++ b/apps/browser/src/autofill/overlay/pages/shared/autofill-overlay-page-element.ts @@ -1,4 +1,5 @@ -import { EVENTS } from "../../../constants"; +import { EVENTS } from "@bitwarden/common/autofill/constants"; + import { RedirectFocusDirection } from "../../../utils/autofill-overlay.enum"; import { AutofillOverlayPageElementWindowMessage, diff --git a/apps/browser/src/autofill/popup/settings/autofill.component.ts b/apps/browser/src/autofill/popup/settings/autofill.component.ts index 9e951e280d..857442d309 100644 --- a/apps/browser/src/autofill/popup/settings/autofill.component.ts +++ b/apps/browser/src/autofill/popup/settings/autofill.component.ts @@ -2,7 +2,9 @@ import { Component, OnInit } from "@angular/core"; import { firstValueFrom } from "rxjs"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; +import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; @@ -12,10 +14,6 @@ import { DialogService } from "@bitwarden/components"; import { BrowserApi } from "../../../platform/browser/browser-api"; import { enableAccountSwitching } from "../../../platform/flags"; import { AutofillService } from "../../services/abstractions/autofill.service"; -import { - AutofillOverlayVisibility, - InlineMenuVisibilitySetting, -} from "../../utils/autofill-overlay.enum"; @Component({ selector: "app-autofill", diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts index e2bc787d3b..4b3641208b 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts @@ -1,17 +1,13 @@ import { mock } from "jest-mock-extended"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; -import { EVENTS } from "../constants"; import AutofillField from "../models/autofill-field"; import { createAutofillFieldMock } from "../spec/autofill-mocks"; import { flushPromises } from "../spec/testing-utils"; import { ElementWithOpId, FormFieldElement } from "../types"; -import { - AutofillOverlayElement, - AutofillOverlayVisibility, - RedirectFocusDirection, -} from "../utils/autofill-overlay.enum"; +import { AutofillOverlayElement, RedirectFocusDirection } from "../utils/autofill-overlay.enum"; import { AutoFillConstants } from "./autofill-constants"; import AutofillOverlayContentService from "./autofill-overlay-content.service"; diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts index 21baf9a3cd..efbc9732b6 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -3,9 +3,9 @@ import "lit/polyfill-support.js"; import { FocusableElement, tabbable } from "tabbable"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { FocusedFieldData } from "../background/abstractions/overlay.background"; -import { EVENTS } from "../constants"; import AutofillField from "../models/autofill-field"; import AutofillOverlayButtonIframe from "../overlay/iframe-content/autofill-overlay-button-iframe"; import AutofillOverlayListIframe from "../overlay/iframe-content/autofill-overlay-list-iframe"; @@ -16,11 +16,7 @@ import { sendExtensionMessage, setElementStyles, } from "../utils"; -import { - AutofillOverlayElement, - RedirectFocusDirection, - AutofillOverlayVisibility, -} from "../utils/autofill-overlay.enum"; +import { AutofillOverlayElement, RedirectFocusDirection } from "../utils/autofill-overlay.enum"; import { AutofillOverlayContentService as AutofillOverlayContentServiceInterface, diff --git a/apps/browser/src/autofill/services/autofill.service.spec.ts b/apps/browser/src/autofill/services/autofill.service.spec.ts index 055e92a31c..4be338da8e 100644 --- a/apps/browser/src/autofill/services/autofill.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill.service.spec.ts @@ -1,6 +1,7 @@ import { mock, mockReset } from "jest-mock-extended"; import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service"; +import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { EventType } from "@bitwarden/common/enums"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -37,7 +38,6 @@ import { createGenerateFillScriptOptionsMock, } from "../spec/autofill-mocks"; import { triggerTestFailure } from "../spec/testing-utils"; -import { AutofillOverlayVisibility } from "../utils/autofill-overlay.enum"; import { AutoFillOptions, diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index 80d8c4f77f..4357a9cb6c 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -4,6 +4,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { EventType } from "@bitwarden/common/enums"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -20,7 +21,6 @@ import { AutofillPort } from "../enums/autofill-port.enums"; import AutofillField from "../models/autofill-field"; import AutofillPageDetails from "../models/autofill-page-details"; import AutofillScript from "../models/autofill-script"; -import { InlineMenuVisibilitySetting } from "../utils/autofill-overlay.enum"; import { AutoFillOptions, diff --git a/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts b/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts index ae41f1c9c2..5ea1284d1b 100644 --- a/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts +++ b/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts @@ -1,4 +1,5 @@ -import { EVENTS } from "../constants"; +import { EVENTS } from "@bitwarden/common/autofill/constants"; + import AutofillScript, { FillScript, FillScriptActions } from "../models/autofill-script"; import { FillableFormFieldElement, FormElementWithAttribute, FormFieldElement } from "../types"; diff --git a/apps/browser/src/autofill/services/insert-autofill-content.service.ts b/apps/browser/src/autofill/services/insert-autofill-content.service.ts index 82af53f7ff..dd14cadfa7 100644 --- a/apps/browser/src/autofill/services/insert-autofill-content.service.ts +++ b/apps/browser/src/autofill/services/insert-autofill-content.service.ts @@ -1,4 +1,5 @@ -import { EVENTS, TYPE_CHECK } from "../constants"; +import { EVENTS, TYPE_CHECK } from "@bitwarden/common/autofill/constants"; + import AutofillScript, { AutofillInsertActions, FillScript } from "../models/autofill-script"; import { FormFieldElement } from "../types"; import { diff --git a/apps/browser/src/autofill/utils/autofill-overlay.enum.ts b/apps/browser/src/autofill/utils/autofill-overlay.enum.ts index 92723f01f9..486d68f754 100644 --- a/apps/browser/src/autofill/utils/autofill-overlay.enum.ts +++ b/apps/browser/src/autofill/utils/autofill-overlay.enum.ts @@ -14,19 +14,4 @@ const RedirectFocusDirection = { Next: "next", } as const; -const AutofillOverlayVisibility = { - Off: 0, - OnButtonClick: 1, - OnFieldFocus: 2, -} as const; - -type InlineMenuVisibilitySetting = - (typeof AutofillOverlayVisibility)[keyof typeof AutofillOverlayVisibility]; - -export { - AutofillOverlayElement, - AutofillOverlayPort, - RedirectFocusDirection, - AutofillOverlayVisibility, - InlineMenuVisibilitySetting, -}; +export { AutofillOverlayElement, AutofillOverlayPort, RedirectFocusDirection }; diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index fd735966fb..88d0e3f90a 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -1,4 +1,5 @@ import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; +import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -15,7 +16,6 @@ import { } from "../auth/popup/utils/auth-popout-window"; import { LockedVaultPendingNotificationsData } from "../autofill/background/abstractions/notification.background"; import { AutofillService } from "../autofill/services/abstractions/autofill.service"; -import { AutofillOverlayVisibility } from "../autofill/utils/autofill-overlay.enum"; import { BrowserApi } from "../platform/browser/browser-api"; import { BrowserStateService } from "../platform/services/abstractions/browser-state.service"; import { BrowserEnvironmentService } from "../platform/services/browser-environment.service"; diff --git a/apps/browser/src/popup/settings/options.component.ts b/apps/browser/src/popup/settings/options.component.ts index d798714b5f..ac416a3493 100644 --- a/apps/browser/src/popup/settings/options.component.ts +++ b/apps/browser/src/popup/settings/options.component.ts @@ -6,6 +6,7 @@ import { SettingsService } from "@bitwarden/common/abstractions/settings.service import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service"; +import { ClearClipboardDelaySetting } from "@bitwarden/common/autofill/types"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; @@ -13,7 +14,6 @@ import { ThemeType } from "@bitwarden/common/platform/enums"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { UriMatchType } from "@bitwarden/common/vault/enums"; -import { ClearClipboardDelaySetting } from "../../../../../apps/browser/src/autofill/constants"; import { enableAccountSwitching } from "../../platform/flags"; @Component({ diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts index 5bf770a218..d1fcb5d439 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts @@ -5,6 +5,7 @@ import { debounceTime, takeUntil } from "rxjs/operators"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -19,7 +20,6 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { PasswordRepromptService } from "@bitwarden/vault"; import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service"; -import { AutofillOverlayVisibility } from "../../../../autofill/utils/autofill-overlay.enum"; import { BrowserApi } from "../../../../platform/browser/browser-api"; import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; import { VaultFilterService } from "../../../services/vault-filter.service"; @@ -123,15 +123,32 @@ export class CurrentTabComponent implements OnInit, OnDestroy { .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe(() => this.searchVault()); - // activate autofill on page load if policy is set - if (await this.getActivateAutofillOnPageLoadFromPolicy()) { + const autofillOnPageLoadOrgPolicy = await firstValueFrom( + this.autofillSettingsService.activateAutofillOnPageLoadFromPolicy$, + ); + const autofillOnPageLoadPolicyToastHasDisplayed = await firstValueFrom( + this.autofillSettingsService.autofillOnPageLoadPolicyToastHasDisplayed$, + ); + + // If the org "autofill on page load" policy is set, set the user setting to match it + // @TODO override user setting instead of overwriting + if (autofillOnPageLoadOrgPolicy === true) { await this.autofillSettingsService.setAutofillOnPageLoad(true); - await this.autofillSettingsService.setActivateAutofillOnPageLoadFromPolicy(false); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("autofillPageLoadPolicyActivated"), - ); + + if (!autofillOnPageLoadPolicyToastHasDisplayed) { + this.platformUtilsService.showToast( + "info", + null, + this.i18nService.t("autofillPageLoadPolicyActivated"), + ); + + await this.autofillSettingsService.setAutofillOnPageLoadPolicyToastHasDisplayed(true); + } + } + + // If the org policy is ever disabled after being enabled, reset the toast notification + if (!autofillOnPageLoadOrgPolicy && autofillOnPageLoadPolicyToastHasDisplayed) { + await this.autofillSettingsService.setAutofillOnPageLoadPolicyToastHasDisplayed(false); } } @@ -303,10 +320,6 @@ export class CurrentTabComponent implements OnInit, OnDestroy { this.router.navigate(["autofill"]); } - private async getActivateAutofillOnPageLoadFromPolicy(): Promise { - return await firstValueFrom(this.autofillSettingsService.activateAutofillOnPageLoadFromPolicy$); - } - async dismissCallout() { await this.autofillSettingsService.setAutofillOnPageLoadCalloutIsDismissed(true); this.showHowToAutofill = false; diff --git a/apps/browser/tsconfig.json b/apps/browser/tsconfig.json index 442e153ef2..a4176be0b0 100644 --- a/apps/browser/tsconfig.json +++ b/apps/browser/tsconfig.json @@ -31,5 +31,9 @@ "strictTemplates": true, "preserveWhitespaces": true }, - "include": ["src", "../../libs/common/src/platform/services/**/*.worker.ts"] + "include": [ + "src", + "../../libs/common/src/platform/services/**/*.worker.ts", + "../../libs/common/src/autofill/constants" + ] } diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index c69f03c23c..8905ddabf8 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -1607,21 +1607,31 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ "windows-core", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" dependencies = [ - "windows-targets 0.52.0", + "windows-result", + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-result" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64" +dependencies = [ + "windows-targets 0.52.4", ] [[package]] @@ -1639,7 +1649,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -1659,17 +1669,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -1680,9 +1690,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -1692,9 +1702,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -1704,9 +1714,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -1716,9 +1726,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -1728,9 +1738,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -1740,9 +1750,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -1752,9 +1762,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winnow" diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index a0b5eb5560..5bb0b0831b 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -33,7 +33,7 @@ napi-build = "=2.0.1" [target.'cfg(windows)'.dependencies] widestring = "=1.0.2" -windows = { version = "=0.52.0", features = [ +windows = { version = "=0.54.0", features = [ "Foundation", "Security_Credentials_UI", "Security_Cryptography", diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 83a2179d58..1bbf0402da 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -24,7 +24,7 @@ "**/node_modules/argon2/package.json", "**/node_modules/argon2/lib/binding/napi-v3/argon2.node" ], - "electronVersion": "28.2.5", + "electronVersion": "28.2.6", "generateUpdatesFilesForAllChannels": true, "publish": { "provider": "generic", diff --git a/apps/desktop/package.json b/apps/desktop/package.json index abc4263faf..ad26e17699 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2024.2.1", + "version": "2024.2.2", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 24c14467a5..663ed211cd 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.2.1", + "version": "2024.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.2.1", + "version": "2024.2.2", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-native": "file:../desktop_native" diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 082e79935e..68d1fbe112 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2024.2.1", + "version": "2024.2.2", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.html b/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.html index 5624618511..569ff91f62 100644 --- a/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.html +++ b/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.html @@ -1,33 +1,30 @@

{{ header }}

- Secure your business with a simpler, faster way to secure and manage secrets + {{ headline }}

-

Limited time offer

+

{{ calloutHeadline }}

    -
  • - Sign up today and receive a complimentary 12-month subscription to Bitwarden Password - Manager +
  • + {{ callout }}
  • -
  • Experience complete security across your organization
  • -
  • Secure all your sensitive credentials, from passwords to machine secrets
diff --git a/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.ts b/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.ts index d190623ae2..20e6c2f849 100644 --- a/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.ts +++ b/apps/web/src/app/auth/trial-initiation/content/secrets-manager-content.component.ts @@ -8,6 +8,38 @@ import { Subject, takeUntil } from "rxjs"; }) export class SecretsManagerContentComponent implements OnInit, OnDestroy { header: string; + headline = + "A simpler, faster way to secure and automate secrets across code and infrastructure deployments"; + primaryPoints: string[]; + calloutHeadline: string; + callouts: string[]; + + private paidPrimaryPoints = [ + "Unlimited secrets, users, and projects", + "Simple and transparent pricing", + "Zero-knowledge, end-to-end encryption", + ]; + + private paidCalloutHeadline = "Limited time offer"; + + private paidCallouts = [ + "Sign up today and receive a complimentary 12-month subscription to Bitwarden Password Manager", + "Experience complete security across your organization", + "Secure all your sensitive credentials, from user applications to machine secrets", + ]; + + private freePrimaryPoints = [ + "Unlimited secrets", + "Simple and transparent pricing", + "Zero-knowledge, end-to-end encryption", + ]; + + private freeCalloutHeadline = "Go beyond developer security!"; + + private freeCallouts = [ + "Your Bitwarden account will also grant complimentary access to Bitwarden Password Manager", + "Extend end-to-end encryption to your personal passwords, addresses, credit cards and notes", + ]; private destroy$ = new Subject(); @@ -23,13 +55,22 @@ export class SecretsManagerContentComponent implements OnInit, OnDestroy { switch (queryParameters.org) { case "enterprise": this.header = "Secrets Manager for Enterprise"; + this.primaryPoints = this.paidPrimaryPoints; + this.calloutHeadline = this.paidCalloutHeadline; + this.callouts = this.paidCallouts; break; case "free": this.header = "Bitwarden Secrets Manager"; + this.primaryPoints = this.freePrimaryPoints; + this.calloutHeadline = this.freeCalloutHeadline; + this.callouts = this.freeCallouts; break; case "teams": case "teamsStarter": this.header = "Secrets Manager for Teams"; + this.primaryPoints = this.paidPrimaryPoints; + this.calloutHeadline = this.paidCalloutHeadline; + this.callouts = this.paidCallouts; break; } }); diff --git a/apps/web/src/app/auth/trial-initiation/secrets-manager/secrets-manager-trial-free-stepper.component.html b/apps/web/src/app/auth/trial-initiation/secrets-manager/secrets-manager-trial-free-stepper.component.html index ed2ed90bab..0b6e44d4eb 100644 --- a/apps/web/src/app/auth/trial-initiation/secrets-manager/secrets-manager-trial-free-stepper.component.html +++ b/apps/web/src/app/auth/trial-initiation/secrets-manager/secrets-manager-trial-free-stepper.component.html @@ -41,14 +41,14 @@
- - + {{ "onboardingImportDataDetailsPartTwoNoOrgs" | i18n }} - - {{ "onboardingImportDataDetailsPartTwoWithOrgs" | i18n }} -

diff --git a/apps/browser/src/autofill/constants.ts b/libs/common/src/autofill/constants/index.ts similarity index 93% rename from apps/browser/src/autofill/constants.ts rename to libs/common/src/autofill/constants/index.ts index da4bae0183..6d5af41a17 100644 --- a/apps/browser/src/autofill/constants.ts +++ b/libs/common/src/autofill/constants/index.ts @@ -32,9 +32,6 @@ export const ClearClipboardDelay = { FiveMinutes: 300, } as const; -export type ClearClipboardDelaySetting = - (typeof ClearClipboardDelay)[keyof typeof ClearClipboardDelay]; - /* Context Menu item Ids */ export const AUTOFILL_CARD_ID = "autofill-card"; export const AUTOFILL_ID = "autofill"; @@ -53,3 +50,9 @@ export const ROOT_ID = "root"; export const SEPARATOR_ID = "separator"; export const NOTIFICATION_BAR_LIFESPAN_MS = 150000; // 150 seconds + +export const AutofillOverlayVisibility = { + Off: 0, + OnButtonClick: 1, + OnFieldFocus: 2, +} as const; diff --git a/libs/common/src/autofill/services/autofill-settings.service.ts b/libs/common/src/autofill/services/autofill-settings.service.ts index 7311617957..7a06eed6fa 100644 --- a/libs/common/src/autofill/services/autofill-settings.service.ts +++ b/libs/common/src/autofill/services/autofill-settings.service.ts @@ -1,16 +1,7 @@ -import { filter, switchMap, tap, firstValueFrom, map, Observable } from "rxjs"; +import { map, Observable } from "rxjs"; -import { - ClearClipboardDelaySetting, - ClearClipboardDelay, -} from "../../../../../apps/browser/src/autofill/constants"; -import { - AutofillOverlayVisibility, - InlineMenuVisibilitySetting, -} from "../../../../../apps/browser/src/autofill/utils/autofill-overlay.enum"; import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; -import { PolicyType } from "../../admin-console/enums/index"; -import { Policy } from "../../admin-console/models/domain/policy"; +import { PolicyType } from "../../admin-console/enums"; import { AUTOFILL_SETTINGS_DISK, AUTOFILL_SETTINGS_DISK_LOCAL, @@ -19,6 +10,8 @@ import { KeyDefinition, StateProvider, } from "../../platform/state"; +import { ClearClipboardDelay, AutofillOverlayVisibility } from "../constants"; +import { ClearClipboardDelaySetting, InlineMenuVisibilitySetting } from "../types"; const AUTOFILL_ON_PAGE_LOAD = new KeyDefinition(AUTOFILL_SETTINGS_DISK, "autofillOnPageLoad", { deserializer: (value: boolean) => value ?? false, @@ -32,10 +25,6 @@ const AUTOFILL_ON_PAGE_LOAD_DEFAULT = new KeyDefinition( }, ); -const AUTO_COPY_TOTP = new KeyDefinition(AUTOFILL_SETTINGS_DISK, "autoCopyTotp", { - deserializer: (value: boolean) => value ?? false, -}); - const AUTOFILL_ON_PAGE_LOAD_CALLOUT_DISMISSED = new KeyDefinition( AUTOFILL_SETTINGS_DISK, "autofillOnPageLoadCalloutIsDismissed", @@ -44,14 +33,18 @@ const AUTOFILL_ON_PAGE_LOAD_CALLOUT_DISMISSED = new KeyDefinition( }, ); -const ACTIVATE_AUTOFILL_ON_PAGE_LOAD_FROM_POLICY = new KeyDefinition( - AUTOFILL_SETTINGS_DISK_LOCAL, - "activateAutofillOnPageLoadFromPolicy", +const AUTOFILL_ON_PAGE_LOAD_POLICY_TOAST_HAS_DISPLAYED = new KeyDefinition( + AUTOFILL_SETTINGS_DISK, + "autofillOnPageLoadPolicyToastHasDisplayed", { deserializer: (value: boolean) => value ?? false, }, ); +const AUTO_COPY_TOTP = new KeyDefinition(AUTOFILL_SETTINGS_DISK, "autoCopyTotp", { + deserializer: (value: boolean) => value ?? false, +}); + const INLINE_MENU_VISIBILITY = new KeyDefinition( AUTOFILL_SETTINGS_DISK_LOCAL, "inlineMenuVisibility", @@ -73,17 +66,17 @@ export abstract class AutofillSettingsServiceAbstraction { setAutofillOnPageLoad: (newValue: boolean) => Promise; autofillOnPageLoadDefault$: Observable; setAutofillOnPageLoadDefault: (newValue: boolean) => Promise; - autoCopyTotp$: Observable; - setAutoCopyTotp: (newValue: boolean) => Promise; autofillOnPageLoadCalloutIsDismissed$: Observable; setAutofillOnPageLoadCalloutIsDismissed: (newValue: boolean) => Promise; activateAutofillOnPageLoadFromPolicy$: Observable; - setActivateAutofillOnPageLoadFromPolicy: (newValue: boolean) => Promise; + setAutofillOnPageLoadPolicyToastHasDisplayed: (newValue: boolean) => Promise; + autofillOnPageLoadPolicyToastHasDisplayed$: Observable; + autoCopyTotp$: Observable; + setAutoCopyTotp: (newValue: boolean) => Promise; inlineMenuVisibility$: Observable; setInlineMenuVisibility: (newValue: InlineMenuVisibilitySetting) => Promise; clearClipboardDelay$: Observable; setClearClipboardDelay: (newValue: ClearClipboardDelaySetting) => Promise; - handleActivateAutofillPolicy: (policies: Observable) => Observable; } export class AutofillSettingsService implements AutofillSettingsServiceAbstraction { @@ -93,15 +86,17 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti private autofillOnPageLoadDefaultState: ActiveUserState; readonly autofillOnPageLoadDefault$: Observable; - private autoCopyTotpState: ActiveUserState; - readonly autoCopyTotp$: Observable; - private autofillOnPageLoadCalloutIsDismissedState: ActiveUserState; readonly autofillOnPageLoadCalloutIsDismissed$: Observable; - private activateAutofillOnPageLoadFromPolicyState: ActiveUserState; readonly activateAutofillOnPageLoadFromPolicy$: Observable; + private autofillOnPageLoadPolicyToastHasDisplayedState: ActiveUserState; + readonly autofillOnPageLoadPolicyToastHasDisplayed$: Observable; + + private autoCopyTotpState: ActiveUserState; + readonly autoCopyTotp$: Observable; + private inlineMenuVisibilityState: GlobalState; readonly inlineMenuVisibility$: Observable; @@ -110,7 +105,7 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti constructor( private stateProvider: StateProvider, - policyService: PolicyService, + private policyService: PolicyService, ) { this.autofillOnPageLoadState = this.stateProvider.getActive(AUTOFILL_ON_PAGE_LOAD); this.autofillOnPageLoad$ = this.autofillOnPageLoadState.state$.pipe(map((x) => x ?? false)); @@ -122,20 +117,25 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti map((x) => x ?? true), ); - this.autoCopyTotpState = this.stateProvider.getActive(AUTO_COPY_TOTP); - this.autoCopyTotp$ = this.autoCopyTotpState.state$.pipe(map((x) => x ?? false)); - this.autofillOnPageLoadCalloutIsDismissedState = this.stateProvider.getActive( AUTOFILL_ON_PAGE_LOAD_CALLOUT_DISMISSED, ); this.autofillOnPageLoadCalloutIsDismissed$ = this.autofillOnPageLoadCalloutIsDismissedState.state$.pipe(map((x) => x ?? false)); - this.activateAutofillOnPageLoadFromPolicyState = this.stateProvider.getActive( - ACTIVATE_AUTOFILL_ON_PAGE_LOAD_FROM_POLICY, + this.activateAutofillOnPageLoadFromPolicy$ = this.policyService.policyAppliesToActiveUser$( + PolicyType.ActivateAutofill, ); - this.activateAutofillOnPageLoadFromPolicy$ = - this.activateAutofillOnPageLoadFromPolicyState.state$.pipe(map((x) => x ?? false)); + + this.autofillOnPageLoadPolicyToastHasDisplayedState = this.stateProvider.getActive( + AUTOFILL_ON_PAGE_LOAD_POLICY_TOAST_HAS_DISPLAYED, + ); + this.autofillOnPageLoadPolicyToastHasDisplayed$ = this.autofillOnPageLoadState.state$.pipe( + map((x) => x ?? false), + ); + + this.autoCopyTotpState = this.stateProvider.getActive(AUTO_COPY_TOTP); + this.autoCopyTotp$ = this.autoCopyTotpState.state$.pipe(map((x) => x ?? false)); this.inlineMenuVisibilityState = this.stateProvider.getGlobal(INLINE_MENU_VISIBILITY); this.inlineMenuVisibility$ = this.inlineMenuVisibilityState.state$.pipe( @@ -146,8 +146,6 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti this.clearClipboardDelay$ = this.clearClipboardDelayState.state$.pipe( map((x) => x ?? ClearClipboardDelay.Never), ); - - policyService.policies$.pipe(this.handleActivateAutofillPolicy.bind(this)).subscribe(); } async setAutofillOnPageLoad(newValue: boolean): Promise { @@ -158,16 +156,16 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti await this.autofillOnPageLoadDefaultState.update(() => newValue); } - async setAutoCopyTotp(newValue: boolean): Promise { - await this.autoCopyTotpState.update(() => newValue); - } - async setAutofillOnPageLoadCalloutIsDismissed(newValue: boolean): Promise { await this.autofillOnPageLoadCalloutIsDismissedState.update(() => newValue); } - async setActivateAutofillOnPageLoadFromPolicy(newValue: boolean): Promise { - await this.activateAutofillOnPageLoadFromPolicyState.update(() => newValue); + async setAutofillOnPageLoadPolicyToastHasDisplayed(newValue: boolean): Promise { + await this.autofillOnPageLoadPolicyToastHasDisplayedState.update(() => newValue); + } + + async setAutoCopyTotp(newValue: boolean): Promise { + await this.autoCopyTotpState.update(() => newValue); } async setInlineMenuVisibility(newValue: InlineMenuVisibilitySetting): Promise { @@ -177,24 +175,4 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti async setClearClipboardDelay(newValue: ClearClipboardDelaySetting): Promise { await this.clearClipboardDelayState.update(() => newValue); } - - /** - * If the ActivateAutofill policy is enabled, save a flag indicating if we need to - * enable Autofill on page load. - */ - handleActivateAutofillPolicy(policies$: Observable): Observable { - return policies$.pipe( - map((policies) => policies.find((p) => p.type == PolicyType.ActivateAutofill && p.enabled)), - filter((p) => p != null), - switchMap(async (_) => [ - await firstValueFrom(this.activateAutofillOnPageLoadFromPolicy$), - await firstValueFrom(this.autofillOnPageLoad$), - ]), - tap(([activated, autofillEnabled]) => { - if (activated === undefined) { - void this.setActivateAutofillOnPageLoadFromPolicy(!autofillEnabled); - } - }), - ); - } } diff --git a/libs/common/src/autofill/types/index.ts b/libs/common/src/autofill/types/index.ts new file mode 100644 index 0000000000..be5d98f4e0 --- /dev/null +++ b/libs/common/src/autofill/types/index.ts @@ -0,0 +1,7 @@ +import { ClearClipboardDelay, AutofillOverlayVisibility } from "../constants"; + +export type ClearClipboardDelaySetting = + (typeof ClearClipboardDelay)[keyof typeof ClearClipboardDelay]; + +export type InlineMenuVisibilitySetting = + (typeof AutofillOverlayVisibility)[keyof typeof AutofillOverlayVisibility]; diff --git a/libs/common/src/state-migrations/migrations/18-move-autofill-settings-to-state-providers.ts b/libs/common/src/state-migrations/migrations/18-move-autofill-settings-to-state-providers.ts index bbd09ae83d..b70e89f9c0 100644 --- a/libs/common/src/state-migrations/migrations/18-move-autofill-settings-to-state-providers.ts +++ b/libs/common/src/state-migrations/migrations/18-move-autofill-settings-to-state-providers.ts @@ -1,7 +1,15 @@ -import { InlineMenuVisibilitySetting } from "../../../../../apps/browser/src/autofill/utils/autofill-overlay.enum"; import { StateDefinitionLike, MigrationHelper } from "../migration-helper"; import { Migrator } from "../migrator"; +const AutofillOverlayVisibility = { + Off: 0, + OnButtonClick: 1, + OnFieldFocus: 2, +} as const; + +type InlineMenuVisibilitySetting = + (typeof AutofillOverlayVisibility)[keyof typeof AutofillOverlayVisibility]; + type ExpectedAccountState = { settings?: { autoFillOnPageLoadDefault?: boolean; diff --git a/libs/common/src/state-migrations/migrations/25-move-clear-clipboard-to-autofill-settings-state-provider.ts b/libs/common/src/state-migrations/migrations/25-move-clear-clipboard-to-autofill-settings-state-provider.ts index fde7ea9037..31c7bc25c7 100644 --- a/libs/common/src/state-migrations/migrations/25-move-clear-clipboard-to-autofill-settings-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/25-move-clear-clipboard-to-autofill-settings-state-provider.ts @@ -1,7 +1,18 @@ -import { ClearClipboardDelaySetting } from "../../../../../apps/browser/src/autofill/constants"; import { StateDefinitionLike, MigrationHelper } from "../migration-helper"; import { Migrator } from "../migrator"; +const ClearClipboardDelay = { + Never: null as null, + TenSeconds: 10, + TwentySeconds: 20, + ThirtySeconds: 30, + OneMinute: 60, + TwoMinutes: 120, + FiveMinutes: 300, +} as const; + +type ClearClipboardDelaySetting = (typeof ClearClipboardDelay)[keyof typeof ClearClipboardDelay]; + type ExpectedAccountState = { settings?: { clearClipboard?: ClearClipboardDelaySetting; diff --git a/libs/common/src/tools/generator/key-definition.spec.ts b/libs/common/src/tools/generator/key-definition.spec.ts index 6ee9288820..735377a5ba 100644 --- a/libs/common/src/tools/generator/key-definition.spec.ts +++ b/libs/common/src/tools/generator/key-definition.spec.ts @@ -5,6 +5,12 @@ import { SUBADDRESS_SETTINGS, PASSPHRASE_SETTINGS, PASSWORD_SETTINGS, + SIMPLE_LOGIN_FORWARDER, + FORWARD_EMAIL_FORWARDER, + FIREFOX_RELAY_FORWARDER, + FASTMAIL_FORWARDER, + DUCK_DUCK_GO_FORWARDER, + ADDY_IO_FORWARDER, } from "./key-definitions"; describe("Key definitions", () => { @@ -48,6 +54,54 @@ describe("Key definitions", () => { }); }); + describe("ADDY_IO_FORWARDER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + const result = ADDY_IO_FORWARDER.deserializer(value); + expect(result).toBe(value); + }); + }); + + describe("DUCK_DUCK_GO_FORWARDER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + const result = DUCK_DUCK_GO_FORWARDER.deserializer(value); + expect(result).toBe(value); + }); + }); + + describe("FASTMAIL_FORWARDER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + const result = FASTMAIL_FORWARDER.deserializer(value); + expect(result).toBe(value); + }); + }); + + describe("FIREFOX_RELAY_FORWARDER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + const result = FIREFOX_RELAY_FORWARDER.deserializer(value); + expect(result).toBe(value); + }); + }); + + describe("FORWARD_EMAIL_FORWARDER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + const result = FORWARD_EMAIL_FORWARDER.deserializer(value); + expect(result).toBe(value); + }); + }); + + describe("SIMPLE_LOGIN_FORWARDER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + const result = SIMPLE_LOGIN_FORWARDER.deserializer(value); + expect(result).toBe(value); + }); + }); + describe("ENCRYPTED_HISTORY", () => { it("should pass through deserialization", () => { const value = {}; diff --git a/libs/common/src/tools/generator/key-definitions.ts b/libs/common/src/tools/generator/key-definitions.ts index fc51e430dd..bb7c4e8a08 100644 --- a/libs/common/src/tools/generator/key-definitions.ts +++ b/libs/common/src/tools/generator/key-definitions.ts @@ -5,6 +5,12 @@ import { GeneratedPasswordHistory } from "./password/generated-password-history" import { PasswordGenerationOptions } from "./password/password-generation-options"; import { CatchallGenerationOptions } from "./username/catchall-generator-options"; import { EffUsernameGenerationOptions } from "./username/eff-username-generator-options"; +import { + ApiOptions, + EmailDomainOptions, + EmailPrefixOptions, + SelfHostedApiOptions, +} from "./username/options/forwarder-options"; import { SubaddressGenerationOptions } from "./username/subaddress-generator-options"; /** plaintext password generation options */ @@ -52,6 +58,54 @@ export const SUBADDRESS_SETTINGS = new KeyDefinition( + GENERATOR_DISK, + "addyIoForwarder", + { + deserializer: (value) => value, + }, +); + +export const DUCK_DUCK_GO_FORWARDER = new KeyDefinition( + GENERATOR_DISK, + "duckDuckGoForwarder", + { + deserializer: (value) => value, + }, +); + +export const FASTMAIL_FORWARDER = new KeyDefinition( + GENERATOR_DISK, + "fastmailForwarder", + { + deserializer: (value) => value, + }, +); + +export const FIREFOX_RELAY_FORWARDER = new KeyDefinition( + GENERATOR_DISK, + "firefoxRelayForwarder", + { + deserializer: (value) => value, + }, +); + +export const FORWARD_EMAIL_FORWARDER = new KeyDefinition( + GENERATOR_DISK, + "forwardEmailForwarder", + { + deserializer: (value) => value, + }, +); + +export const SIMPLE_LOGIN_FORWARDER = new KeyDefinition( + GENERATOR_DISK, + "simpleLoginForwarder", + { + deserializer: (value) => value, + }, +); + /** encrypted password generation history */ export const ENCRYPTED_HISTORY = new KeyDefinition( GENERATOR_DISK, diff --git a/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts b/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts new file mode 100644 index 0000000000..96a7bca2b1 --- /dev/null +++ b/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts @@ -0,0 +1,73 @@ +import { mock } from "jest-mock-extended"; + +import { FakeStateProvider, mockAccountServiceWith } from "../../../../spec"; +import { CryptoService } from "../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../platform/abstractions/encrypt.service"; +import { StateProvider } from "../../../platform/state"; +import { UserId } from "../../../types/guid"; +import { DefaultPolicyEvaluator } from "../default-policy-evaluator"; +import { DUCK_DUCK_GO_FORWARDER } from "../key-definitions"; +import { SecretState } from "../state/secret-state"; + +import { ForwarderGeneratorStrategy } from "./forwarder-generator-strategy"; +import { ApiOptions } from "./options/forwarder-options"; + +class TestForwarder extends ForwarderGeneratorStrategy { + constructor( + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } + + get key() { + // arbitrary. + return DUCK_DUCK_GO_FORWARDER; + } +} + +const SomeUser = "some user" as UserId; +const AnotherUser = "another user" as UserId; + +describe("ForwarderGeneratorStrategy", () => { + const encryptService = mock(); + const keyService = mock(); + const stateProvider = new FakeStateProvider(mockAccountServiceWith(SomeUser)); + + describe("durableState", () => { + it("constructs a secret state", () => { + const strategy = new TestForwarder(encryptService, keyService, stateProvider); + + const result = strategy.durableState(SomeUser); + + expect(result).toBeInstanceOf(SecretState); + }); + + it("returns the same secret state for a single user", () => { + const strategy = new TestForwarder(encryptService, keyService, stateProvider); + + const firstResult = strategy.durableState(SomeUser); + const secondResult = strategy.durableState(SomeUser); + + expect(firstResult).toBe(secondResult); + }); + + it("returns a different secret state for a different user", () => { + const strategy = new TestForwarder(encryptService, keyService, stateProvider); + + const firstResult = strategy.durableState(SomeUser); + const secondResult = strategy.durableState(AnotherUser); + + expect(firstResult).not.toBe(secondResult); + }); + }); + + it("evaluator returns the default policy evaluator", () => { + const strategy = new TestForwarder(null, null, null); + + const result = strategy.evaluator(null); + + expect(result).toBeInstanceOf(DefaultPolicyEvaluator); + }); +}); diff --git a/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts b/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts new file mode 100644 index 0000000000..554bbfca62 --- /dev/null +++ b/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts @@ -0,0 +1,73 @@ +import { PolicyType } from "../../../admin-console/enums"; +import { Policy } from "../../../admin-console/models/domain/policy"; +import { CryptoService } from "../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../platform/abstractions/encrypt.service"; +import { KeyDefinition, StateProvider } from "../../../platform/state"; +import { UserId } from "../../../types/guid"; +import { GeneratorStrategy } from "../abstractions"; +import { DefaultPolicyEvaluator } from "../default-policy-evaluator"; +import { NoPolicy } from "../no-policy"; +import { PaddedDataPacker } from "../state/padded-data-packer"; +import { SecretClassifier } from "../state/secret-classifier"; +import { SecretState } from "../state/secret-state"; +import { UserKeyEncryptor } from "../state/user-key-encryptor"; + +import { ApiOptions } from "./options/forwarder-options"; + +const ONE_MINUTE = 60 * 1000; +const OPTIONS_FRAME_SIZE = 512; + +/** An email forwarding service configurable through an API. */ +export abstract class ForwarderGeneratorStrategy< + Options extends ApiOptions, +> extends GeneratorStrategy { + /** Initializes the generator strategy + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage + */ + constructor( + private readonly encryptService: EncryptService, + private readonly keyService: CryptoService, + private stateProvider: StateProvider, + ) { + super(); + // Uses password generator since there aren't policies + // specific to usernames. + this.policy = PolicyType.PasswordGenerator; + + this.cache_ms = ONE_MINUTE; + } + + private durableStates = new Map>>(); + + /** {@link GeneratorStrategy.durableState} */ + durableState = (userId: UserId) => { + let state = this.durableStates.get(userId); + + if (!state) { + const encryptor = this.createEncryptor(); + state = SecretState.from(userId, this.key, this.stateProvider, encryptor); + this.durableStates.set(userId, state); + } + + return state; + }; + + private createEncryptor() { + // always exclude request properties + const classifier = SecretClassifier.allSecret().exclude("website"); + + // construct the encryptor + const packer = new PaddedDataPacker(OPTIONS_FRAME_SIZE); + return new UserKeyEncryptor(this.encryptService, this.keyService, classifier, packer); + } + + /** Determine where forwarder configuration is stored */ + protected abstract readonly key: KeyDefinition; + + /** {@link GeneratorStrategy.evaluator} */ + evaluator = (_policy: Policy) => { + return new DefaultPolicyEvaluator(); + }; +} diff --git a/libs/common/src/tools/generator/username/forwarders/addy-io.spec.ts b/libs/common/src/tools/generator/username/forwarders/addy-io.spec.ts index cc742dc920..c2428aefca 100644 --- a/libs/common/src/tools/generator/username/forwarders/addy-io.spec.ts +++ b/libs/common/src/tools/generator/username/forwarders/addy-io.spec.ts @@ -2,22 +2,30 @@ * include Request in test environment. * @jest-environment ../../../../shared/test.environment.ts */ +import { ADDY_IO_FORWARDER } from "../../key-definitions"; import { Forwarders } from "../options/constants"; import { AddyIoForwarder } from "./addy-io"; import { mockApiService, mockI18nService } from "./mocks.jest"; describe("Addy.io Forwarder", () => { + it("key returns the Addy IO forwarder key", () => { + const forwarder = new AddyIoForwarder(null, null, null, null, null); + + expect(forwarder.key).toBe(ADDY_IO_FORWARDER); + }); + describe("generate(string | null, SelfHostedApiOptions & EmailDomainOptions)", () => { it.each([null, ""])("throws an error if the token is missing (token = %p)", async (token) => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token, domain: "example.com", baseUrl: "https://api.example.com", @@ -34,11 +42,12 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain, baseUrl: "https://api.example.com", @@ -56,11 +65,12 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", baseUrl, @@ -83,9 +93,10 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); - await forwarder.generate(website, { + await forwarder.generate({ + website, token: "token", domain: "example.com", baseUrl: "https://api.example.com", @@ -107,9 +118,10 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(status, { data: { email } }); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); - const result = await forwarder.generate(null, { + const result = await forwarder.generate({ + website: null, token: "token", domain: "example.com", baseUrl: "https://api.example.com", @@ -124,11 +136,12 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(401, {}); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", baseUrl: "https://api.example.com", @@ -148,11 +161,12 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(500, {}); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", baseUrl: "https://api.example.com", @@ -181,11 +195,12 @@ describe("Addy.io Forwarder", () => { const apiService = mockApiService(statusCode, {}, statusText); const i18nService = mockI18nService(); - const forwarder = new AddyIoForwarder(apiService, i18nService); + const forwarder = new AddyIoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", baseUrl: "https://api.example.com", diff --git a/libs/common/src/tools/generator/username/forwarders/addy-io.ts b/libs/common/src/tools/generator/username/forwarders/addy-io.ts index 96e02033fe..2db69e2396 100644 --- a/libs/common/src/tools/generator/username/forwarders/addy-io.ts +++ b/libs/common/src/tools/generator/username/forwarders/addy-io.ts @@ -1,24 +1,41 @@ import { ApiService } from "../../../../abstractions/api.service"; +import { CryptoService } from "../../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../../platform/abstractions/i18n.service"; +import { StateProvider } from "../../../../platform/state"; +import { ADDY_IO_FORWARDER } from "../../key-definitions"; +import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; -import { EmailDomainOptions, Forwarder, SelfHostedApiOptions } from "../options/forwarder-options"; +import { EmailDomainOptions, SelfHostedApiOptions } from "../options/forwarder-options"; /** Generates a forwarding address for addy.io (formerly anon addy) */ -export class AddyIoForwarder implements Forwarder { +export class AddyIoForwarder extends ForwarderGeneratorStrategy< + SelfHostedApiOptions & EmailDomainOptions +> { /** Instantiates the forwarder * @param apiService used for ajax requests to the forwarding service * @param i18nService used to look up error strings + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage */ constructor( private apiService: ApiService, private i18nService: I18nService, - ) {} + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } - /** {@link Forwarder.generate} */ - async generate( - website: string | null, - options: SelfHostedApiOptions & EmailDomainOptions, - ): Promise { + /** {@link ForwarderGeneratorStrategy.key} */ + get key() { + return ADDY_IO_FORWARDER; + } + + /** {@link ForwarderGeneratorStrategy.generate} */ + generate = async (options: SelfHostedApiOptions & EmailDomainOptions) => { if (!options.token || options.token === "") { const error = this.i18nService.t("forwaderInvalidToken", Forwarders.AddyIo.name); throw error; @@ -32,9 +49,11 @@ export class AddyIoForwarder implements Forwarder { throw error; } - const descriptionId = - website && website !== "" ? "forwarderGeneratedByWithWebsite" : "forwarderGeneratedBy"; - const description = this.i18nService.t(descriptionId, website ?? ""); + let descriptionId = "forwarderGeneratedByWithWebsite"; + if (!options.website || options.website === "") { + descriptionId = "forwarderGeneratedBy"; + } + const description = this.i18nService.t(descriptionId, options.website ?? ""); const url = options.baseUrl + "/api/v1/aliases"; const request = new Request(url, { @@ -70,5 +89,5 @@ export class AddyIoForwarder implements Forwarder { const error = this.i18nService.t("forwarderUnknownError", Forwarders.AddyIo.name); throw error; } - } + }; } diff --git a/libs/common/src/tools/generator/username/forwarders/duck-duck-go.spec.ts b/libs/common/src/tools/generator/username/forwarders/duck-duck-go.spec.ts index 7b5765f9a7..211eaead6d 100644 --- a/libs/common/src/tools/generator/username/forwarders/duck-duck-go.spec.ts +++ b/libs/common/src/tools/generator/username/forwarders/duck-duck-go.spec.ts @@ -2,22 +2,30 @@ * include Request in test environment. * @jest-environment ../../../../shared/test.environment.ts */ +import { DUCK_DUCK_GO_FORWARDER } from "../../key-definitions"; import { Forwarders } from "../options/constants"; import { DuckDuckGoForwarder } from "./duck-duck-go"; import { mockApiService, mockI18nService } from "./mocks.jest"; describe("DuckDuckGo Forwarder", () => { + it("key returns the Duck Duck Go forwarder key", () => { + const forwarder = new DuckDuckGoForwarder(null, null, null, null, null); + + expect(forwarder.key).toBe(DUCK_DUCK_GO_FORWARDER); + }); + describe("generate(string | null, SelfHostedApiOptions & EmailDomainOptions)", () => { it.each([null, ""])("throws an error if the token is missing (token = %p)", async (token) => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new DuckDuckGoForwarder(apiService, i18nService); + const forwarder = new DuckDuckGoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token, }), ).rejects.toEqual("forwaderInvalidToken"); @@ -40,9 +48,10 @@ describe("DuckDuckGo Forwarder", () => { const apiService = mockApiService(status, { address }); const i18nService = mockI18nService(); - const forwarder = new DuckDuckGoForwarder(apiService, i18nService); + const forwarder = new DuckDuckGoForwarder(apiService, i18nService, null, null, null); - const result = await forwarder.generate(null, { + const result = await forwarder.generate({ + website: null, token: "token", }); @@ -55,11 +64,12 @@ describe("DuckDuckGo Forwarder", () => { const apiService = mockApiService(401, {}); const i18nService = mockI18nService(); - const forwarder = new DuckDuckGoForwarder(apiService, i18nService); + const forwarder = new DuckDuckGoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", }), ).rejects.toEqual("forwaderInvalidToken"); @@ -76,11 +86,12 @@ describe("DuckDuckGo Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new DuckDuckGoForwarder(apiService, i18nService); + const forwarder = new DuckDuckGoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", }), ).rejects.toEqual("forwarderUnknownError"); @@ -99,11 +110,12 @@ describe("DuckDuckGo Forwarder", () => { const apiService = mockApiService(statusCode, {}); const i18nService = mockI18nService(); - const forwarder = new DuckDuckGoForwarder(apiService, i18nService); + const forwarder = new DuckDuckGoForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", }), ).rejects.toEqual("forwarderUnknownError"); diff --git a/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts b/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts index 8078230b3a..daf4f7b444 100644 --- a/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts +++ b/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts @@ -1,21 +1,39 @@ import { ApiService } from "../../../../abstractions/api.service"; +import { CryptoService } from "../../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../../platform/abstractions/i18n.service"; +import { StateProvider } from "../../../../platform/state"; +import { DUCK_DUCK_GO_FORWARDER } from "../../key-definitions"; +import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; -import { ApiOptions, Forwarder } from "../options/forwarder-options"; +import { ApiOptions } from "../options/forwarder-options"; /** Generates a forwarding address for DuckDuckGo */ -export class DuckDuckGoForwarder implements Forwarder { +export class DuckDuckGoForwarder extends ForwarderGeneratorStrategy { /** Instantiates the forwarder * @param apiService used for ajax requests to the forwarding service * @param i18nService used to look up error strings + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage */ constructor( private apiService: ApiService, private i18nService: I18nService, - ) {} + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } - /** {@link Forwarder.generate} */ - async generate(_website: string | null, options: ApiOptions): Promise { + /** {@link ForwarderGeneratorStrategy.key} */ + get key() { + return DUCK_DUCK_GO_FORWARDER; + } + + /** {@link ForwarderGeneratorStrategy.generate} */ + generate = async (options: ApiOptions): Promise => { if (!options.token || options.token === "") { const error = this.i18nService.t("forwaderInvalidToken", Forwarders.DuckDuckGo.name); throw error; @@ -48,5 +66,5 @@ export class DuckDuckGoForwarder implements Forwarder { const error = this.i18nService.t("forwarderUnknownError", Forwarders.DuckDuckGo.name); throw error; } - } + }; } diff --git a/libs/common/src/tools/generator/username/forwarders/fastmail.spec.ts b/libs/common/src/tools/generator/username/forwarders/fastmail.spec.ts index 6d557399aa..bab2b93966 100644 --- a/libs/common/src/tools/generator/username/forwarders/fastmail.spec.ts +++ b/libs/common/src/tools/generator/username/forwarders/fastmail.spec.ts @@ -3,6 +3,7 @@ * @jest-environment ../../../../shared/test.environment.ts */ import { ApiService } from "../../../../abstractions/api.service"; +import { FASTMAIL_FORWARDER } from "../../key-definitions"; import { Forwarders } from "../options/constants"; import { FastmailForwarder } from "./fastmail"; @@ -45,16 +46,23 @@ const AccountIdSuccess: MockResponse = Object.freeze({ // the tests describe("Fastmail Forwarder", () => { + it("key returns the Fastmail forwarder key", () => { + const forwarder = new FastmailForwarder(null, null, null, null, null); + + expect(forwarder.key).toBe(FASTMAIL_FORWARDER); + }); + describe("generate(string | null, SelfHostedApiOptions & EmailDomainOptions)", () => { it.each([null, ""])("throws an error if the token is missing (token = %p)", async (token) => { const apiService = mockApiService(AccountIdSuccess, EmptyResponse); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token, domain: "example.com", prefix: "prefix", @@ -71,11 +79,12 @@ describe("Fastmail Forwarder", () => { const apiService = mockApiService({ status, body: {} }, EmptyResponse); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", prefix: "prefix", @@ -105,9 +114,10 @@ describe("Fastmail Forwarder", () => { }); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); - const result = await forwarder.generate(null, { + const result = await forwarder.generate({ + website: null, token: "token", domain: "example.com", prefix: "prefix", @@ -138,11 +148,12 @@ describe("Fastmail Forwarder", () => { }); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", prefix: "prefix", @@ -165,11 +176,12 @@ describe("Fastmail Forwarder", () => { const apiService = mockApiService(AccountIdSuccess, { status, body: {} }); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", prefix: "prefix", @@ -206,11 +218,12 @@ describe("Fastmail Forwarder", () => { }); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", prefix: "prefix", @@ -232,11 +245,12 @@ describe("Fastmail Forwarder", () => { const apiService = mockApiService(AccountIdSuccess, { status: statusCode, body: {} }); const i18nService = mockI18nService(); - const forwarder = new FastmailForwarder(apiService, i18nService); + const forwarder = new FastmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", prefix: "prefix", diff --git a/libs/common/src/tools/generator/username/forwarders/fastmail.ts b/libs/common/src/tools/generator/username/forwarders/fastmail.ts index b6b40946a8..b4e2b56695 100644 --- a/libs/common/src/tools/generator/username/forwarders/fastmail.ts +++ b/libs/common/src/tools/generator/username/forwarders/fastmail.ts @@ -1,24 +1,39 @@ import { ApiService } from "../../../../abstractions/api.service"; +import { CryptoService } from "../../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../../platform/abstractions/i18n.service"; +import { StateProvider } from "../../../../platform/state"; +import { FASTMAIL_FORWARDER } from "../../key-definitions"; +import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; -import { EmailPrefixOptions, Forwarder, ApiOptions } from "../options/forwarder-options"; +import { EmailPrefixOptions, ApiOptions } from "../options/forwarder-options"; /** Generates a forwarding address for Fastmail */ -export class FastmailForwarder implements Forwarder { +export class FastmailForwarder extends ForwarderGeneratorStrategy { /** Instantiates the forwarder * @param apiService used for ajax requests to the forwarding service * @param i18nService used to look up error strings + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage */ constructor( private apiService: ApiService, private i18nService: I18nService, - ) {} + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } - /** {@link Forwarder.generate} */ - async generate( - website: string | null, - options: ApiOptions & EmailPrefixOptions, - ): Promise { + /** {@link ForwarderGeneratorStrategy.key} */ + get key() { + return FASTMAIL_FORWARDER; + } + + /** {@link ForwarderGeneratorStrategy.generate} */ + generate = async (options: ApiOptions & EmailPrefixOptions) => { if (!options.token || options.token === "") { const error = this.i18nService.t("forwaderInvalidToken", Forwarders.Fastmail.name); throw error; @@ -41,7 +56,7 @@ export class FastmailForwarder implements Forwarder { "new-masked-email": { state: "enabled", description: "", - forDomain: website, + forDomain: options.website, emailPrefix: options.prefix, }, }, @@ -104,7 +119,7 @@ export class FastmailForwarder implements Forwarder { const error = this.i18nService.t("forwarderUnknownError", Forwarders.Fastmail.name); throw error; - } + }; private async getAccountId(options: ApiOptions): Promise { const requestInit: RequestInit = { diff --git a/libs/common/src/tools/generator/username/forwarders/firefox-relay.spec.ts b/libs/common/src/tools/generator/username/forwarders/firefox-relay.spec.ts index b5c1c66d6d..5ba8d3f2f1 100644 --- a/libs/common/src/tools/generator/username/forwarders/firefox-relay.spec.ts +++ b/libs/common/src/tools/generator/username/forwarders/firefox-relay.spec.ts @@ -2,22 +2,30 @@ * include Request in test environment. * @jest-environment ../../../../shared/test.environment.ts */ +import { FIREFOX_RELAY_FORWARDER } from "../../key-definitions"; import { Forwarders } from "../options/constants"; import { FirefoxRelayForwarder } from "./firefox-relay"; import { mockApiService, mockI18nService } from "./mocks.jest"; describe("Firefox Relay Forwarder", () => { + it("key returns the Firefox Relay forwarder key", () => { + const forwarder = new FirefoxRelayForwarder(null, null, null, null, null); + + expect(forwarder.key).toBe(FIREFOX_RELAY_FORWARDER); + }); + describe("generate(string | null, SelfHostedApiOptions & EmailDomainOptions)", () => { it.each([null, ""])("throws an error if the token is missing (token = %p)", async (token) => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new FirefoxRelayForwarder(apiService, i18nService); + const forwarder = new FirefoxRelayForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token, }), ).rejects.toEqual("forwaderInvalidToken"); @@ -40,9 +48,10 @@ describe("Firefox Relay Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new FirefoxRelayForwarder(apiService, i18nService); + const forwarder = new FirefoxRelayForwarder(apiService, i18nService, null, null, null); - await forwarder.generate(website, { + await forwarder.generate({ + website, token: "token", }); @@ -62,9 +71,10 @@ describe("Firefox Relay Forwarder", () => { const apiService = mockApiService(status, { full_address }); const i18nService = mockI18nService(); - const forwarder = new FirefoxRelayForwarder(apiService, i18nService); + const forwarder = new FirefoxRelayForwarder(apiService, i18nService, null, null, null); - const result = await forwarder.generate(null, { + const result = await forwarder.generate({ + website: null, token: "token", }); @@ -77,11 +87,12 @@ describe("Firefox Relay Forwarder", () => { const apiService = mockApiService(401, {}); const i18nService = mockI18nService(); - const forwarder = new FirefoxRelayForwarder(apiService, i18nService); + const forwarder = new FirefoxRelayForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", }), ).rejects.toEqual("forwaderInvalidToken"); @@ -101,11 +112,12 @@ describe("Firefox Relay Forwarder", () => { const apiService = mockApiService(statusCode, {}); const i18nService = mockI18nService(); - const forwarder = new FirefoxRelayForwarder(apiService, i18nService); + const forwarder = new FirefoxRelayForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", }), ).rejects.toEqual("forwarderUnknownError"); diff --git a/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts b/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts index 1bb19ed7fe..1308852224 100644 --- a/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts +++ b/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts @@ -1,21 +1,39 @@ import { ApiService } from "../../../../abstractions/api.service"; +import { CryptoService } from "../../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../../platform/abstractions/i18n.service"; +import { StateProvider } from "../../../../platform/state"; +import { FIREFOX_RELAY_FORWARDER } from "../../key-definitions"; +import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; -import { Forwarder, ApiOptions } from "../options/forwarder-options"; +import { ApiOptions } from "../options/forwarder-options"; /** Generates a forwarding address for Firefox Relay */ -export class FirefoxRelayForwarder implements Forwarder { +export class FirefoxRelayForwarder extends ForwarderGeneratorStrategy { /** Instantiates the forwarder * @param apiService used for ajax requests to the forwarding service * @param i18nService used to look up error strings + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage */ constructor( private apiService: ApiService, private i18nService: I18nService, - ) {} + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } - /** {@link Forwarder.generate} */ - async generate(website: string | null, options: ApiOptions): Promise { + /** {@link ForwarderGeneratorStrategy.key} */ + get key() { + return FIREFOX_RELAY_FORWARDER; + } + + /** {@link ForwarderGeneratorStrategy.generate} */ + generate = async (options: ApiOptions) => { if (!options.token || options.token === "") { const error = this.i18nService.t("forwaderInvalidToken", Forwarders.FirefoxRelay.name); throw error; @@ -23,9 +41,11 @@ export class FirefoxRelayForwarder implements Forwarder { const url = "https://relay.firefox.com/api/v1/relayaddresses/"; - const descriptionId = - website && website !== "" ? "forwarderGeneratedByWithWebsite" : "forwarderGeneratedBy"; - const description = this.i18nService.t(descriptionId, website ?? ""); + let descriptionId = "forwarderGeneratedByWithWebsite"; + if (!options.website || options.website === "") { + descriptionId = "forwarderGeneratedBy"; + } + const description = this.i18nService.t(descriptionId, options.website ?? ""); const request = new Request(url, { redirect: "manual", @@ -37,7 +57,7 @@ export class FirefoxRelayForwarder implements Forwarder { }), body: JSON.stringify({ enabled: true, - generated_for: website, + generated_for: options.website, description, }), }); @@ -53,5 +73,5 @@ export class FirefoxRelayForwarder implements Forwarder { const error = this.i18nService.t("forwarderUnknownError", Forwarders.FirefoxRelay.name); throw error; } - } + }; } diff --git a/libs/common/src/tools/generator/username/forwarders/forward-email.spec.ts b/libs/common/src/tools/generator/username/forwarders/forward-email.spec.ts index a5c2e14d37..daf0f3d7f1 100644 --- a/libs/common/src/tools/generator/username/forwarders/forward-email.spec.ts +++ b/libs/common/src/tools/generator/username/forwarders/forward-email.spec.ts @@ -2,22 +2,30 @@ * include Request in test environment. * @jest-environment ../../../../shared/test.environment.ts */ +import { FORWARD_EMAIL_FORWARDER } from "../../key-definitions"; import { Forwarders } from "../options/constants"; import { ForwardEmailForwarder } from "./forward-email"; import { mockApiService, mockI18nService } from "./mocks.jest"; describe("ForwardEmail Forwarder", () => { + it("key returns the Forward Email forwarder key", () => { + const forwarder = new ForwardEmailForwarder(null, null, null, null, null); + + expect(forwarder.key).toBe(FORWARD_EMAIL_FORWARDER); + }); + describe("generate(string | null, SelfHostedApiOptions & EmailDomainOptions)", () => { it.each([null, ""])("throws an error if the token is missing (token = %p)", async (token) => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token, domain: "example.com", }), @@ -36,11 +44,12 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain, }), @@ -65,9 +74,10 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); - await forwarder.generate(website, { + await forwarder.generate({ + website, token: "token", domain: "example.com", }); @@ -92,9 +102,10 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(status, response); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); - const result = await forwarder.generate(null, { + const result = await forwarder.generate({ + website: null, token: "token", domain: "example.com", }); @@ -108,11 +119,12 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(401, {}); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", }), @@ -132,11 +144,12 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(401, { message: "A message" }); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", }), @@ -158,11 +171,12 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(500, json); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", }), @@ -191,11 +205,12 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(statusCode, { message }); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", }), @@ -225,11 +240,12 @@ describe("ForwardEmail Forwarder", () => { const apiService = mockApiService(statusCode, { error }); const i18nService = mockI18nService(); - const forwarder = new ForwardEmailForwarder(apiService, i18nService); + const forwarder = new ForwardEmailForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", domain: "example.com", }), diff --git a/libs/common/src/tools/generator/username/forwarders/forward-email.ts b/libs/common/src/tools/generator/username/forwarders/forward-email.ts index 7fc727e471..eb6e3cd0c6 100644 --- a/libs/common/src/tools/generator/username/forwarders/forward-email.ts +++ b/libs/common/src/tools/generator/username/forwarders/forward-email.ts @@ -1,25 +1,42 @@ import { ApiService } from "../../../../abstractions/api.service"; +import { CryptoService } from "../../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { Utils } from "../../../../platform/misc/utils"; +import { StateProvider } from "../../../../platform/state"; +import { FORWARD_EMAIL_FORWARDER } from "../../key-definitions"; +import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; -import { EmailDomainOptions, Forwarder, ApiOptions } from "../options/forwarder-options"; +import { EmailDomainOptions, ApiOptions } from "../options/forwarder-options"; /** Generates a forwarding address for Forward Email */ -export class ForwardEmailForwarder implements Forwarder { +export class ForwardEmailForwarder extends ForwarderGeneratorStrategy< + ApiOptions & EmailDomainOptions +> { /** Instantiates the forwarder * @param apiService used for ajax requests to the forwarding service * @param i18nService used to look up error strings + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage */ constructor( private apiService: ApiService, private i18nService: I18nService, - ) {} + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } - /** {@link Forwarder.generate} */ - async generate( - website: string | null, - options: ApiOptions & EmailDomainOptions, - ): Promise { + /** {@link ForwarderGeneratorStrategy.key} */ + get key() { + return FORWARD_EMAIL_FORWARDER; + } + + /** {@link ForwarderGeneratorStrategy.generate} */ + generate = async (options: ApiOptions & EmailDomainOptions) => { if (!options.token || options.token === "") { const error = this.i18nService.t("forwaderInvalidToken", Forwarders.ForwardEmail.name); throw error; @@ -31,9 +48,11 @@ export class ForwardEmailForwarder implements Forwarder { const url = `https://api.forwardemail.net/v1/domains/${options.domain}/aliases`; - const descriptionId = - website && website !== "" ? "forwarderGeneratedByWithWebsite" : "forwarderGeneratedBy"; - const description = this.i18nService.t(descriptionId, website ?? ""); + let descriptionId = "forwarderGeneratedByWithWebsite"; + if (!options.website || options.website === "") { + descriptionId = "forwarderGeneratedBy"; + } + const description = this.i18nService.t(descriptionId, options.website ?? ""); const request = new Request(url, { redirect: "manual", @@ -44,7 +63,7 @@ export class ForwardEmailForwarder implements Forwarder { "Content-Type": "application/json", }), body: JSON.stringify({ - labels: website, + labels: options.website, description, }), }); @@ -75,5 +94,5 @@ export class ForwardEmailForwarder implements Forwarder { const error = this.i18nService.t("forwarderUnknownError", Forwarders.ForwardEmail.name); throw error; } - } + }; } diff --git a/libs/common/src/tools/generator/username/forwarders/simple-login.spec.ts b/libs/common/src/tools/generator/username/forwarders/simple-login.spec.ts index 60ca329e8b..1120d49ce3 100644 --- a/libs/common/src/tools/generator/username/forwarders/simple-login.spec.ts +++ b/libs/common/src/tools/generator/username/forwarders/simple-login.spec.ts @@ -2,22 +2,30 @@ * include Request in test environment. * @jest-environment ../../../../shared/test.environment.ts */ +import { SIMPLE_LOGIN_FORWARDER } from "../../key-definitions"; import { Forwarders } from "../options/constants"; import { mockApiService, mockI18nService } from "./mocks.jest"; import { SimpleLoginForwarder } from "./simple-login"; describe("SimpleLogin Forwarder", () => { + it("key returns the Simple Login forwarder key", () => { + const forwarder = new SimpleLoginForwarder(null, null, null, null, null); + + expect(forwarder.key).toBe(SIMPLE_LOGIN_FORWARDER); + }); + describe("generate(string | null, SelfHostedApiOptions & EmailDomainOptions)", () => { it.each([null, ""])("throws an error if the token is missing (token = %p)", async (token) => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token, baseUrl: "https://api.example.com", }), @@ -36,11 +44,12 @@ describe("SimpleLogin Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", baseUrl, }), @@ -62,9 +71,10 @@ describe("SimpleLogin Forwarder", () => { const apiService = mockApiService(200, {}); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); - await forwarder.generate(website, { + await forwarder.generate({ + website, token: "token", baseUrl: "https://api.example.com", }); @@ -85,9 +95,10 @@ describe("SimpleLogin Forwarder", () => { const apiService = mockApiService(status, { alias }); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); - const result = await forwarder.generate(null, { + const result = await forwarder.generate({ + website: null, token: "token", baseUrl: "https://api.example.com", }); @@ -101,11 +112,12 @@ describe("SimpleLogin Forwarder", () => { const apiService = mockApiService(401, {}); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", baseUrl: "https://api.example.com", }), @@ -126,11 +138,12 @@ describe("SimpleLogin Forwarder", () => { const apiService = mockApiService(500, body); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", baseUrl: "https://api.example.com", }), @@ -159,11 +172,12 @@ describe("SimpleLogin Forwarder", () => { const apiService = mockApiService(statusCode, { error }); const i18nService = mockI18nService(); - const forwarder = new SimpleLoginForwarder(apiService, i18nService); + const forwarder = new SimpleLoginForwarder(apiService, i18nService, null, null, null); await expect( async () => - await forwarder.generate(null, { + await forwarder.generate({ + website: null, token: "token", baseUrl: "https://api.example.com", }), diff --git a/libs/common/src/tools/generator/username/forwarders/simple-login.ts b/libs/common/src/tools/generator/username/forwarders/simple-login.ts index 0000b680e3..33bd8e3d4e 100644 --- a/libs/common/src/tools/generator/username/forwarders/simple-login.ts +++ b/libs/common/src/tools/generator/username/forwarders/simple-login.ts @@ -1,21 +1,39 @@ import { ApiService } from "../../../../abstractions/api.service"; +import { CryptoService } from "../../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../../platform/abstractions/encrypt.service"; import { I18nService } from "../../../../platform/abstractions/i18n.service"; +import { StateProvider } from "../../../../platform/state"; +import { SIMPLE_LOGIN_FORWARDER } from "../../key-definitions"; +import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; -import { Forwarder, SelfHostedApiOptions } from "../options/forwarder-options"; +import { SelfHostedApiOptions } from "../options/forwarder-options"; /** Generates a forwarding address for Simple Login */ -export class SimpleLoginForwarder implements Forwarder { +export class SimpleLoginForwarder extends ForwarderGeneratorStrategy { /** Instantiates the forwarder * @param apiService used for ajax requests to the forwarding service * @param i18nService used to look up error strings + * @param encryptService protects sensitive forwarder options + * @param keyService looks up the user key when protecting data. + * @param stateProvider creates the durable state for options storage */ constructor( private apiService: ApiService, private i18nService: I18nService, - ) {} + encryptService: EncryptService, + keyService: CryptoService, + stateProvider: StateProvider, + ) { + super(encryptService, keyService, stateProvider); + } - /** {@link Forwarder.generate} */ - async generate(website: string, options: SelfHostedApiOptions): Promise { + /** {@link ForwarderGeneratorStrategy.key} */ + get key() { + return SIMPLE_LOGIN_FORWARDER; + } + + /** {@link ForwarderGeneratorStrategy.generate} */ + generate = async (options: SelfHostedApiOptions) => { if (!options.token || options.token === "") { const error = this.i18nService.t("forwaderInvalidToken", Forwarders.SimpleLogin.name); throw error; @@ -27,11 +45,11 @@ export class SimpleLoginForwarder implements Forwarder { let url = options.baseUrl + "/api/alias/random/new"; let noteId = "forwarderGeneratedBy"; - if (website && website !== "") { - url += "?hostname=" + website; + if (options.website && options.website !== "") { + url += "?hostname=" + options.website; noteId = "forwarderGeneratedByWithWebsite"; } - const note = this.i18nService.t(noteId, website ?? ""); + const note = this.i18nService.t(noteId, options.website ?? ""); const request = new Request(url, { redirect: "manual", @@ -60,5 +78,5 @@ export class SimpleLoginForwarder implements Forwarder { const error = this.i18nService.t("forwarderUnknownError", Forwarders.SimpleLogin.name); throw error; } - } + }; } diff --git a/libs/common/src/tools/generator/username/options/constants.ts b/libs/common/src/tools/generator/username/options/constants.ts index 66f5d83af9..8f7013d48b 100644 --- a/libs/common/src/tools/generator/username/options/constants.ts +++ b/libs/common/src/tools/generator/username/options/constants.ts @@ -85,27 +85,33 @@ export const DefaultOptions: UsernameGeneratorOptions = Object.freeze({ forwarders: Object.freeze({ service: Forwarders.Fastmail.id, fastMail: Object.freeze({ + website: null, domain: "", prefix: "", token: "", }), addyIo: Object.freeze({ + website: null, baseUrl: "https://app.addy.io", domain: "", token: "", }), forwardEmail: Object.freeze({ + website: null, token: "", domain: "", }), simpleLogin: Object.freeze({ + website: null, baseUrl: "https://app.simplelogin.io", token: "", }), duckDuckGo: Object.freeze({ + website: null, token: "", }), firefoxRelay: Object.freeze({ + website: null, token: "", }), }), diff --git a/libs/common/src/tools/generator/username/options/forwarder-options.ts b/libs/common/src/tools/generator/username/options/forwarder-options.ts index 02375726c8..f36a58a0db 100644 --- a/libs/common/src/tools/generator/username/options/forwarder-options.ts +++ b/libs/common/src/tools/generator/username/options/forwarder-options.ts @@ -1,5 +1,3 @@ -import { EncString } from "../../../../platform/models/domain/enc-string"; - /** Identifiers for email forwarding services. * @remarks These are used to select forwarder-specific options. * The must be kept in sync with the forwarder implementations. @@ -24,26 +22,24 @@ export type ForwarderMetadata = { validForSelfHosted: boolean; }; -/** An email forwarding service configurable through an API. */ -export interface Forwarder { - /** Generate a forwarding email. - * @param website The website to generate a username for. - * @param options The options to use when generating the username. - */ - generate(website: string | null, options: ApiOptions): Promise; -} - /** Options common to all forwarder APIs */ export type ApiOptions = { /** bearer token that authenticates bitwarden to the forwarder. * This is required to issue an API request. */ token?: string; +} & RequestOptions; - /** encrypted bearer token that authenticates bitwarden to the forwarder. - * This is used to store the token at rest and must be decoded before use. +/** Options that provide contextual information about the application state + * when a forwarder is invoked. + * @remarks these fields should always be omitted when saving options. + */ +export type RequestOptions = { + /** @param website The domain of the website the generated email is used + * within. This should be set to `null` when the request is not specific + * to any website. */ - encryptedToken?: EncString; + website: string | null; }; /** Api configuration for forwarders that support self-hosted installations. */ diff --git a/libs/common/src/tools/generator/username/options/utilities.spec.ts b/libs/common/src/tools/generator/username/options/utilities.spec.ts index 904ac6dbfc..7ab1d9dcfd 100644 --- a/libs/common/src/tools/generator/username/options/utilities.spec.ts +++ b/libs/common/src/tools/generator/username/options/utilities.spec.ts @@ -24,27 +24,33 @@ const TestOptions: UsernameGeneratorOptions = { forwarders: { service: Forwarders.Fastmail.id, fastMail: { + website: null, domain: "httpbin.com", prefix: "foo", token: "some-token", }, addyIo: { + website: null, baseUrl: "https://app.addy.io", domain: "example.com", token: "some-token", }, forwardEmail: { + website: null, token: "some-token", domain: "example.com", }, simpleLogin: { + website: null, baseUrl: "https://app.simplelogin.io", token: "some-token", }, duckDuckGo: { + website: null, token: "some-token", }, firefoxRelay: { + website: null, token: "some-token", }, }, diff --git a/package-lock.json b/package-lock.json index b2e201684d..b4ba333c87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,7 +94,7 @@ "@storybook/jest": "0.2.3", "@storybook/testing-library": "0.2.2", "@types/argon2-browser": "1.18.1", - "@types/chrome": "0.0.243", + "@types/chrome": "0.0.262", "@types/duo_web_sdk": "2.7.1", "@types/firefox-webext-browser": "111.0.1", "@types/inquirer": "8.2.10", @@ -128,7 +128,7 @@ "copy-webpack-plugin": "11.0.0", "cross-env": "7.0.3", "css-loader": "6.8.1", - "electron": "28.2.5", + "electron": "28.2.6", "electron-builder": "24.9.1", "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", @@ -234,7 +234,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.2.1", + "version": "2024.2.2", "hasInstallScript": true, "license": "GPL-3.0" }, @@ -10867,9 +10867,9 @@ } }, "node_modules/@types/chrome": { - "version": "0.0.243", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.243.tgz", - "integrity": "sha512-4PHv0kxxxpZFHWPBiJJ9TWH8kbx0567j1b2djnhpJjpiSGNI7UKkz7dSEECBtQ0B3N5nQTMwSB/5IopkWGAbEA==", + "version": "0.0.262", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.262.tgz", + "integrity": "sha512-TOoj3dqSYE13PD2fRuMQ6X6pggEvL9rRk/yOYOyWE6sfqRWxsJm4VoVm+wr9pkr4Sht/M5t7FFL4vXato8d1gA==", "dev": true, "dependencies": { "@types/filesystem": "*", @@ -17807,9 +17807,9 @@ } }, "node_modules/electron": { - "version": "28.2.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-28.2.5.tgz", - "integrity": "sha512-qlvQkDNVAzN647NpiJJw7GYJqE0NwK4+1evkhrQ0Xv6Qgab1EtN50G4oDr4/x/+O5pGUG2P5d3isXu+37O3RDw==", + "version": "28.2.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-28.2.6.tgz", + "integrity": "sha512-RuhbW+ifvh3DqnVlHCcCKhKIFOxTktq1GN1gkIkEZ8y5LEZfcjOkxB2s6Fd1S6MzsMZbiJti+ZJG5hXS4SDVLQ==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/package.json b/package.json index ea1f7d318f..7d273fa495 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@storybook/jest": "0.2.3", "@storybook/testing-library": "0.2.2", "@types/argon2-browser": "1.18.1", - "@types/chrome": "0.0.243", + "@types/chrome": "0.0.262", "@types/duo_web_sdk": "2.7.1", "@types/firefox-webext-browser": "111.0.1", "@types/inquirer": "8.2.10", @@ -89,7 +89,7 @@ "copy-webpack-plugin": "11.0.0", "cross-env": "7.0.3", "css-loader": "6.8.1", - "electron": "28.2.5", + "electron": "28.2.6", "electron-builder": "24.9.1", "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1",