mirror of
https://github.com/bitwarden/browser.git
synced 2025-03-12 13:39:14 +01:00
Merge branch 'main' into autofill/pm-6546-blurring-of-autofilled-elements-causes-problems-in-blur-event-listeners
This commit is contained in:
commit
ab734d2281
2
.github/workflows/brew-bump-cli.yml
vendored
2
.github/workflows/brew-bump-cli.yml
vendored
@ -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 }}
|
||||
|
2
.github/workflows/build-browser.yml
vendored
2
.github/workflows/build-browser.yml
vendored
@ -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 }}
|
||||
|
2
.github/workflows/build-cli.yml
vendored
2
.github/workflows/build-cli.yml
vendored
@ -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
|
||||
|
36
.github/workflows/build-desktop.yml
vendored
36
.github/workflows/build-desktop.yml
vendored
@ -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 }}
|
||||
|
4
.github/workflows/build-web.yml
vendored
4
.github/workflows/build-web.yml
vendored
@ -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 }}
|
||||
|
4
.github/workflows/chromatic.yml
vendored
4
.github/workflows/chromatic.yml
vendored
@ -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 }}
|
||||
|
33
.github/workflows/deploy-web.yml
vendored
33
.github/workflows/deploy-web.yml
vendored
@ -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 }}
|
||||
|
4
.github/workflows/release-browser.yml
vendored
4
.github/workflows/release-browser.yml
vendored
@ -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'
|
||||
|
4
.github/workflows/release-cli.yml
vendored
4
.github/workflows/release-cli.yml
vendored
@ -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'
|
||||
|
30
.github/workflows/release-desktop-beta.yml
vendored
30
.github/workflows/release-desktop-beta.yml
vendored
@ -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'
|
||||
|
4
.github/workflows/release-desktop.yml
vendored
4
.github/workflows/release-desktop.yml
vendored
@ -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'
|
||||
|
4
.github/workflows/release-web.yml
vendored
4
.github/workflows/release-web.yml
vendored
@ -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
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -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 }}
|
||||
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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 };
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { EVENTS } from "../../../constants";
|
||||
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
||||
|
||||
import { RedirectFocusDirection } from "../../../utils/autofill-overlay.enum";
|
||||
import {
|
||||
AutofillOverlayPageElementWindowMessage,
|
||||
|
@ -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",
|
||||
|
@ -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";
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 };
|
||||
|
@ -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";
|
||||
|
@ -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({
|
||||
|
@ -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<boolean> {
|
||||
return await firstValueFrom(this.autofillSettingsService.activateAutofillOnPageLoadFromPolicy$);
|
||||
}
|
||||
|
||||
async dismissCallout() {
|
||||
await this.autofillSettingsService.setAutofillOnPageLoadCalloutIsDismissed(true);
|
||||
this.showHowToAutofill = false;
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
70
apps/desktop/desktop_native/Cargo.lock
generated
70
apps/desktop/desktop_native/Cargo.lock
generated
@ -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"
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
4
apps/desktop/src/package-lock.json
generated
4
apps/desktop/src/package-lock.json
generated
@ -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"
|
||||
|
@ -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. <hello@bitwarden.com> (https://bitwarden.com)",
|
||||
"homepage": "https://bitwarden.com",
|
||||
"license": "GPL-3.0",
|
||||
|
@ -1,33 +1,30 @@
|
||||
<h1 class="tw-text-4xl !tw-text-alt2">{{ header }}</h1>
|
||||
<div class="tw-pt-16">
|
||||
<h2 class="tw-text-2xl tw-font-semibold">
|
||||
Secure your business with a simpler, faster way to secure and manage secrets
|
||||
{{ headline }}
|
||||
</h2>
|
||||
</div>
|
||||
<ul class="tw-mt-12 tw-flex tw-flex-col tw-gap-10 tw-text-2xl tw-text-main">
|
||||
<li>Unlimited secrets, users, and projects</li>
|
||||
<li>Simple and transparent pricing</li>
|
||||
<li>End-to-end encryption</li>
|
||||
<li *ngFor="let primaryPoint of primaryPoints">
|
||||
{{ primaryPoint }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tw-mt-12 tw-flex tw-flex-col">
|
||||
<div class="tw-rounded-[32px] tw-bg-background">
|
||||
<div class="tw-my-8 tw-mx-6">
|
||||
<h2 class="tw-pl-5 tw-font-semibold">Limited time offer</h2>
|
||||
<h2 class="tw-pl-5 tw-font-semibold">{{ calloutHeadline }}</h2>
|
||||
<ul class="tw-space-y-4 tw-mt-4 tw-pl-10">
|
||||
<li>
|
||||
Sign up today and receive a complimentary 12-month subscription to Bitwarden Password
|
||||
Manager
|
||||
<li *ngFor="let callout of callouts">
|
||||
{{ callout }}
|
||||
</li>
|
||||
<li>Experience complete security across your organization</li>
|
||||
<li>Secure all your sensitive credentials, from passwords to machine secrets</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tw-mt-12 tw-flex tw-flex-col tw-items-center tw-gap-5">
|
||||
<app-review-blurb
|
||||
header="Businesses trust Bitwarden to secure their secrets"
|
||||
header="Businesses trust Bitwarden to secure their infrastructure"
|
||||
quote="At this point, it would be almost impossible to leak our secrets. It's just one less thing we have to worry about."
|
||||
source="Head of IT, Titanom Technologies"
|
||||
source="Titanom Technologies"
|
||||
></app-review-blurb>
|
||||
</div>
|
||||
|
@ -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<void>();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
});
|
||||
|
@ -41,14 +41,14 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tw-mb-3 tw-flex">
|
||||
<button type="button" bitButton buttonType="primary" (click)="navigateTo('vault')">
|
||||
<button type="button" bitButton buttonType="primary" (click)="navigateToSecretsManager()">
|
||||
{{ "getStarted" | i18n | titlecase }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitButton
|
||||
buttonType="secondary"
|
||||
(click)="navigateTo('members')"
|
||||
(click)="navigateToMembers()"
|
||||
class="tw-ml-3 tw-inline-flex tw-items-center tw-px-3"
|
||||
>
|
||||
{{ "inviteUsers" | i18n }}
|
||||
|
@ -78,7 +78,11 @@ export class SecretsManagerTrialFreeStepperComponent implements OnInit {
|
||||
this.verticalStepper.next();
|
||||
}
|
||||
|
||||
async navigateTo(organizationRoute: string): Promise<void> {
|
||||
await this.router.navigate(["organizations", this.organizationId, organizationRoute]);
|
||||
async navigateToMembers(): Promise<void> {
|
||||
await this.router.navigate(["organizations", this.organizationId, "members"]);
|
||||
}
|
||||
|
||||
async navigateToSecretsManager(): Promise<void> {
|
||||
await this.router.navigate(["sm", this.organizationId]);
|
||||
}
|
||||
}
|
||||
|
@ -46,14 +46,14 @@
|
||||
[orgLabel]="organizationTypeQueryParameter"
|
||||
></app-trial-confirmation-details>
|
||||
<div class="tw-mb-3 tw-flex">
|
||||
<button type="button" bitButton buttonType="primary" (click)="navigateTo('vault')">
|
||||
<button type="button" bitButton buttonType="primary" (click)="navigateToSecretsManager()">
|
||||
{{ "getStarted" | i18n | titlecase }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitButton
|
||||
buttonType="secondary"
|
||||
(click)="navigateTo('members')"
|
||||
(click)="navigateToMembers()"
|
||||
class="tw-ml-3 tw-inline-flex tw-items-center tw-px-3"
|
||||
>
|
||||
{{ "inviteUsers" | i18n }}
|
||||
|
@ -27,12 +27,9 @@
|
||||
<button type="button" bitLink (click)="emitToAddCipher()">
|
||||
{{ "onboardingImportDataDetailsLink" | i18n }}
|
||||
</button>
|
||||
<span *ngIf="orgs == null || orgs.length === 0">
|
||||
<span>
|
||||
{{ "onboardingImportDataDetailsPartTwoNoOrgs" | i18n }}
|
||||
</span>
|
||||
<span *ngIf="orgs.length > 0">
|
||||
{{ "onboardingImportDataDetailsPartTwoWithOrgs" | i18n }}
|
||||
</span>
|
||||
</p>
|
||||
</app-onboarding-task>
|
||||
|
||||
|
@ -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;
|
@ -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<void>;
|
||||
autofillOnPageLoadDefault$: Observable<boolean>;
|
||||
setAutofillOnPageLoadDefault: (newValue: boolean) => Promise<void>;
|
||||
autoCopyTotp$: Observable<boolean>;
|
||||
setAutoCopyTotp: (newValue: boolean) => Promise<void>;
|
||||
autofillOnPageLoadCalloutIsDismissed$: Observable<boolean>;
|
||||
setAutofillOnPageLoadCalloutIsDismissed: (newValue: boolean) => Promise<void>;
|
||||
activateAutofillOnPageLoadFromPolicy$: Observable<boolean>;
|
||||
setActivateAutofillOnPageLoadFromPolicy: (newValue: boolean) => Promise<void>;
|
||||
setAutofillOnPageLoadPolicyToastHasDisplayed: (newValue: boolean) => Promise<void>;
|
||||
autofillOnPageLoadPolicyToastHasDisplayed$: Observable<boolean>;
|
||||
autoCopyTotp$: Observable<boolean>;
|
||||
setAutoCopyTotp: (newValue: boolean) => Promise<void>;
|
||||
inlineMenuVisibility$: Observable<InlineMenuVisibilitySetting>;
|
||||
setInlineMenuVisibility: (newValue: InlineMenuVisibilitySetting) => Promise<void>;
|
||||
clearClipboardDelay$: Observable<ClearClipboardDelaySetting>;
|
||||
setClearClipboardDelay: (newValue: ClearClipboardDelaySetting) => Promise<void>;
|
||||
handleActivateAutofillPolicy: (policies: Observable<Policy[]>) => Observable<boolean[]>;
|
||||
}
|
||||
|
||||
export class AutofillSettingsService implements AutofillSettingsServiceAbstraction {
|
||||
@ -93,15 +86,17 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti
|
||||
private autofillOnPageLoadDefaultState: ActiveUserState<boolean>;
|
||||
readonly autofillOnPageLoadDefault$: Observable<boolean>;
|
||||
|
||||
private autoCopyTotpState: ActiveUserState<boolean>;
|
||||
readonly autoCopyTotp$: Observable<boolean>;
|
||||
|
||||
private autofillOnPageLoadCalloutIsDismissedState: ActiveUserState<boolean>;
|
||||
readonly autofillOnPageLoadCalloutIsDismissed$: Observable<boolean>;
|
||||
|
||||
private activateAutofillOnPageLoadFromPolicyState: ActiveUserState<boolean>;
|
||||
readonly activateAutofillOnPageLoadFromPolicy$: Observable<boolean>;
|
||||
|
||||
private autofillOnPageLoadPolicyToastHasDisplayedState: ActiveUserState<boolean>;
|
||||
readonly autofillOnPageLoadPolicyToastHasDisplayed$: Observable<boolean>;
|
||||
|
||||
private autoCopyTotpState: ActiveUserState<boolean>;
|
||||
readonly autoCopyTotp$: Observable<boolean>;
|
||||
|
||||
private inlineMenuVisibilityState: GlobalState<InlineMenuVisibilitySetting>;
|
||||
readonly inlineMenuVisibility$: Observable<InlineMenuVisibilitySetting>;
|
||||
|
||||
@ -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<void> {
|
||||
@ -158,16 +156,16 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti
|
||||
await this.autofillOnPageLoadDefaultState.update(() => newValue);
|
||||
}
|
||||
|
||||
async setAutoCopyTotp(newValue: boolean): Promise<void> {
|
||||
await this.autoCopyTotpState.update(() => newValue);
|
||||
}
|
||||
|
||||
async setAutofillOnPageLoadCalloutIsDismissed(newValue: boolean): Promise<void> {
|
||||
await this.autofillOnPageLoadCalloutIsDismissedState.update(() => newValue);
|
||||
}
|
||||
|
||||
async setActivateAutofillOnPageLoadFromPolicy(newValue: boolean): Promise<void> {
|
||||
await this.activateAutofillOnPageLoadFromPolicyState.update(() => newValue);
|
||||
async setAutofillOnPageLoadPolicyToastHasDisplayed(newValue: boolean): Promise<void> {
|
||||
await this.autofillOnPageLoadPolicyToastHasDisplayedState.update(() => newValue);
|
||||
}
|
||||
|
||||
async setAutoCopyTotp(newValue: boolean): Promise<void> {
|
||||
await this.autoCopyTotpState.update(() => newValue);
|
||||
}
|
||||
|
||||
async setInlineMenuVisibility(newValue: InlineMenuVisibilitySetting): Promise<void> {
|
||||
@ -177,24 +175,4 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti
|
||||
async setClearClipboardDelay(newValue: ClearClipboardDelaySetting): Promise<void> {
|
||||
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<Policy[]>): Observable<boolean[]> {
|
||||
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);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
7
libs/common/src/autofill/types/index.ts
Normal file
7
libs/common/src/autofill/types/index.ts
Normal file
@ -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];
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 = {};
|
||||
|
@ -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<SubaddressGenerationOptions
|
||||
},
|
||||
);
|
||||
|
||||
export const ADDY_IO_FORWARDER = new KeyDefinition<SelfHostedApiOptions & EmailDomainOptions>(
|
||||
GENERATOR_DISK,
|
||||
"addyIoForwarder",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
export const DUCK_DUCK_GO_FORWARDER = new KeyDefinition<ApiOptions>(
|
||||
GENERATOR_DISK,
|
||||
"duckDuckGoForwarder",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
export const FASTMAIL_FORWARDER = new KeyDefinition<ApiOptions & EmailPrefixOptions>(
|
||||
GENERATOR_DISK,
|
||||
"fastmailForwarder",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
export const FIREFOX_RELAY_FORWARDER = new KeyDefinition<ApiOptions>(
|
||||
GENERATOR_DISK,
|
||||
"firefoxRelayForwarder",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
export const FORWARD_EMAIL_FORWARDER = new KeyDefinition<ApiOptions & EmailDomainOptions>(
|
||||
GENERATOR_DISK,
|
||||
"forwardEmailForwarder",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
export const SIMPLE_LOGIN_FORWARDER = new KeyDefinition<SelfHostedApiOptions>(
|
||||
GENERATOR_DISK,
|
||||
"simpleLoginForwarder",
|
||||
{
|
||||
deserializer: (value) => value,
|
||||
},
|
||||
);
|
||||
|
||||
/** encrypted password generation history */
|
||||
export const ENCRYPTED_HISTORY = new KeyDefinition<GeneratedPasswordHistory>(
|
||||
GENERATOR_DISK,
|
||||
|
@ -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<ApiOptions> {
|
||||
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<EncryptService>();
|
||||
const keyService = mock<CryptoService>();
|
||||
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);
|
||||
});
|
||||
});
|
@ -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<Options, NoPolicy> {
|
||||
/** 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<UserId, SecretState<Options, Record<string, never>>>();
|
||||
|
||||
/** {@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<Options>().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<Options>;
|
||||
|
||||
/** {@link GeneratorStrategy.evaluator} */
|
||||
evaluator = (_policy: Policy) => {
|
||||
return new DefaultPolicyEvaluator<Options>();
|
||||
};
|
||||
}
|
@ -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",
|
||||
|
@ -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<string> {
|
||||
/** {@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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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<ApiOptions> {
|
||||
/** 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<string> {
|
||||
/** {@link ForwarderGeneratorStrategy.key} */
|
||||
get key() {
|
||||
return DUCK_DUCK_GO_FORWARDER;
|
||||
}
|
||||
|
||||
/** {@link ForwarderGeneratorStrategy.generate} */
|
||||
generate = async (options: ApiOptions): Promise<string> => {
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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<ApiOptions & EmailPrefixOptions> {
|
||||
/** 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<string> {
|
||||
/** {@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<string> {
|
||||
const requestInit: RequestInit = {
|
||||
|
@ -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");
|
||||
|
@ -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<ApiOptions> {
|
||||
/** 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<string> {
|
||||
/** {@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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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",
|
||||
}),
|
||||
|
@ -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<string> {
|
||||
/** {@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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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",
|
||||
}),
|
||||
|
@ -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<SelfHostedApiOptions> {
|
||||
/** 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<string> {
|
||||
/** {@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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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: "",
|
||||
}),
|
||||
}),
|
||||
|
@ -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<string>;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
|
@ -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",
|
||||
},
|
||||
},
|
||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -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": {
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user