mirror of
https://github.com/bitwarden/browser.git
synced 2025-04-14 20:07:04 +02:00
Merged branch with master
This commit is contained in:
commit
91324876c6
@ -156,7 +156,10 @@
|
||||
{
|
||||
"files": ["libs/components/src/**/*.ts"],
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/components/*", "src/**/*"] }]
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{ "patterns": ["@bitwarden/components/*", "src/**/*", "@bitwarden/angular/*"] }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -176,6 +179,12 @@
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/node/*", "src/**/*"] }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["libs/vault/src/**/*.ts"],
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/vault/*", "src/**/*"] }]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
# The following owners will be the default owners for everything in the repo.
|
||||
# Unless a later match takes precedence
|
||||
* @bitwarden/team-leads-eng
|
||||
* @bitwarden/tech-leads
|
||||
|
||||
## Secrets Manager team files ##
|
||||
bitwarden_license/bit-web/src/app/secrets-manager @bitwarden/team-secrets-manager-dev
|
||||
@ -39,6 +39,7 @@ apps/desktop/src/vault @bitwarden/team-vault-dev
|
||||
apps/web/src/app/vault @bitwarden/team-vault-dev
|
||||
libs/angular/src/vault @bitwarden/team-vault-dev
|
||||
libs/common/src/vault @bitwarden/team-vault-dev
|
||||
libs/vault @bitwarden/team-vault-dev
|
||||
|
||||
## Admin Console team files ##
|
||||
apps/browser/src/admin-console @bitwarden/team-admin-console-dev
|
||||
|
9
.github/whitelist-capital-letters.txt
vendored
9
.github/whitelist-capital-letters.txt
vendored
@ -2,10 +2,7 @@
|
||||
./apps/browser/src/safari/desktop/Assets.xcassets/AccentColor.colorset
|
||||
./apps/browser/src/safari/desktop/Assets.xcassets/AppIcon.appiconset
|
||||
./apps/browser/src/safari/desktop/Base.lproj
|
||||
./apps/browser/src/services/vaultTimeout
|
||||
./apps/browser/store/windows/Assets
|
||||
./libs/common/src/abstractions/vaultTimeout
|
||||
./libs/common/src/services/vaultTimeout
|
||||
./bitwarden_license/README.md
|
||||
./libs/angular/src/directives/cipherListVirtualScroll.directive.ts
|
||||
./libs/angular/src/scss/webfonts/Open_Sans-italic-700.woff
|
||||
@ -25,13 +22,10 @@
|
||||
./libs/common/src/misc/linkedFieldOption.decorator.ts
|
||||
./libs/common/src/misc/serviceUtils.ts
|
||||
./libs/common/src/misc/serviceUtils.spec.ts
|
||||
./libs/common/src/abstractions/vaultTimeout/vaultTimeoutSettings.service.ts
|
||||
./libs/common/src/abstractions/vaultTimeout/vaultTimeout.service.ts
|
||||
./libs/common/src/abstractions/anonymousHub.service.ts
|
||||
./libs/common/src/services/vaultTimeout/vaultTimeoutSettings.service.ts
|
||||
./libs/common/src/services/vaultTimeout/vaultTimeout.service.ts
|
||||
./libs/common/src/services/anonymousHub.service.ts
|
||||
./libs/auth/README.md
|
||||
./libs/vault/README.md
|
||||
./README.md
|
||||
./LICENSE_BITWARDEN.txt
|
||||
./CONTRIBUTING.md
|
||||
@ -78,5 +72,4 @@
|
||||
./apps/browser/src/safari/safari/SafariWebExtensionHandler.swift
|
||||
./apps/browser/src/safari/safari/Info.plist
|
||||
./apps/browser/src/safari/desktop.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
|
||||
./apps/browser/src/services/vaultTimeout/vaultTimeout.service.ts
|
||||
./SECURITY.md
|
||||
|
79
.github/workflows/build-web.yml
vendored
79
.github/workflows/build-web.yml
vendored
@ -31,6 +31,9 @@ on:
|
||||
description: "Custom image tag extension"
|
||||
required: false
|
||||
|
||||
env:
|
||||
_AZ_REGISTRY: bitwardenprod.azurecr.io
|
||||
|
||||
jobs:
|
||||
cloc:
|
||||
name: CLOC
|
||||
@ -65,8 +68,7 @@ jobs:
|
||||
build-artifacts:
|
||||
name: Build artifacts
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- setup
|
||||
needs: setup
|
||||
env:
|
||||
_VERSION: ${{ needs.setup.outputs.version }}
|
||||
strategy:
|
||||
@ -146,13 +148,10 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- artifact_name: cloud-QA
|
||||
registries: [bitwardenprod.azurecr.io, bitwardenqa.azurecr.io]
|
||||
image_name: web-qa-cloud
|
||||
- artifact_name: ee
|
||||
registries: [bitwardenprod.azurecr.io, bitwardenqa.azurecr.io]
|
||||
image_name: web-ee
|
||||
- artifact_name: selfhosted-COMMERCIAL
|
||||
registries: [bitwarden, bitwardenprod.azurecr.io, bitwardenqa.azurecr.io]
|
||||
image_name: web
|
||||
env:
|
||||
_VERSION: ${{ needs.setup.outputs.version }}
|
||||
@ -174,15 +173,7 @@ jobs:
|
||||
fi
|
||||
|
||||
########## ACRs ##########
|
||||
- name: Login to Azure - QA
|
||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }}
|
||||
|
||||
- name: Log into QA container registry
|
||||
run: az acr login -n bitwardenqa
|
||||
|
||||
- name: Login to Azure - Prod
|
||||
- name: Login to Prod Azure
|
||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
@ -190,6 +181,18 @@ jobs:
|
||||
- name: Log into Prod container registry
|
||||
run: az acr login -n bitwardenprod
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve github PAT secrets
|
||||
id: retrieve-secret-pat
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@f096207b7a2f31723165aee6ad03e91716686e78
|
||||
with:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||
|
||||
- name: Download ${{ matrix.artifact_name }} artifact
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
with:
|
||||
@ -218,37 +221,17 @@ jobs:
|
||||
|
||||
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate tag list
|
||||
id: tag-list
|
||||
env:
|
||||
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
|
||||
PROJECT_NAME: ${{ matrix.image_name }}
|
||||
run: echo "tags=bitwardenqa.azurecr.io/${PROJECT_NAME}:${IMAGE_TAG},bitwardenprod.azurecr.io/${PROJECT_NAME}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
|
||||
|
||||
########## Build Image ##########
|
||||
- name: Extract artifact
|
||||
working-directory: apps/web
|
||||
run: unzip web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip
|
||||
|
||||
- name: Login to Azure
|
||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve github PAT secrets
|
||||
id: retrieve-secret-pat
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@a30e9c3d658dc97c4c2e61ec749fdab64b83386c
|
||||
with:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||
|
||||
- name: Setup DCT
|
||||
if: ${{ env.is_publish_branch == 'true' }}
|
||||
id: setup-dct
|
||||
uses: bitwarden/gh-actions/setup-docker-trust@a30e9c3d658dc97c4c2e61ec749fdab64b83386c
|
||||
with:
|
||||
azure-creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
azure-keyvault-name: "bitwarden-ci"
|
||||
- name: Generate image full name
|
||||
id: image-name
|
||||
env:
|
||||
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
|
||||
PROJECT_NAME: ${{ matrix.image_name }}
|
||||
run: echo "name=$_AZ_REGISTRY/${PROJECT_NAME}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4.1.1
|
||||
@ -257,21 +240,10 @@ jobs:
|
||||
file: apps/web/Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.tag-list.outputs.tags }}
|
||||
tags: ${{ steps.image-name.outputs.name }}
|
||||
secrets: |
|
||||
"GH_PAT=${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}"
|
||||
|
||||
- name: Push to DockerHub
|
||||
if: contains(matrix.registries, 'bitwarden') && env.is_publish_branch == 'true'
|
||||
env:
|
||||
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
|
||||
PROJECT_NAME: ${{ matrix.image_name }}
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
||||
run: |
|
||||
docker tag bitwardenprod.azurecr.io/$PROJECT_NAME:$IMAGE_TAG bitwarden/$PROJECT_NAME:$IMAGE_TAG
|
||||
docker push bitwarden/$PROJECT_NAME:$IMAGE_TAG
|
||||
|
||||
- name: Log out of Docker
|
||||
run: docker logout
|
||||
|
||||
@ -279,8 +251,7 @@ jobs:
|
||||
crowdin-push:
|
||||
name: Crowdin Push
|
||||
if: github.ref == 'refs/heads/master'
|
||||
needs:
|
||||
- build-artifacts
|
||||
needs: build-artifacts
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
|
96
.github/workflows/release-web.yml
vendored
96
.github/workflows/release-web.yml
vendored
@ -15,10 +15,13 @@ on:
|
||||
- Redeploy
|
||||
- Dry Run
|
||||
|
||||
env:
|
||||
_AZ_REGISTRY: bitwardenprod.azurecr.io
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
name: Setup
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
release_version: ${{ steps.version.outputs.version }}
|
||||
tag_version: ${{ steps.version.outputs.tag }}
|
||||
@ -46,10 +49,9 @@ jobs:
|
||||
monorepo: true
|
||||
monorepo-project: web
|
||||
|
||||
|
||||
self-host:
|
||||
name: Release self-host docker
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: setup
|
||||
env:
|
||||
_BRANCH_NAME: ${{ github.ref_name }}
|
||||
@ -67,42 +69,6 @@ jobs:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
|
||||
########## DockerHub ##########
|
||||
- name: Setup DCT
|
||||
id: setup-dct
|
||||
uses: bitwarden/gh-actions/setup-docker-trust@a30e9c3d658dc97c4c2e61ec749fdab64b83386c
|
||||
with:
|
||||
azure-creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
azure-keyvault-name: "bitwarden-ci"
|
||||
|
||||
- name: Pull branch image
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker pull bitwarden/web:latest
|
||||
else
|
||||
docker pull bitwarden/web:$_BRANCH_NAME
|
||||
fi
|
||||
|
||||
- name: Docker Tag version
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker tag bitwarden/web:latest bitwarden/web:$_RELEASE_VERSION
|
||||
else
|
||||
docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:$_RELEASE_VERSION
|
||||
fi
|
||||
|
||||
- name: Docker Push version
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }}
|
||||
run: docker push bitwarden/web:$_RELEASE_VERSION
|
||||
|
||||
- name: Log out of Docker and disable Docker Notary
|
||||
run: |
|
||||
docker logout
|
||||
echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV
|
||||
|
||||
########## ACR ##########
|
||||
- name: Login to Azure - PROD Subscription
|
||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
||||
@ -112,38 +78,46 @@ jobs:
|
||||
- name: Login to Azure ACR
|
||||
run: az acr login -n bitwardenprod
|
||||
|
||||
- name: Tag version
|
||||
env:
|
||||
REGISTRY: bitwardenprod.azurecr.io
|
||||
- name: Pull branch image
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker tag bitwarden/web:latest $REGISTRY/web:$_RELEASE_VERSION
|
||||
|
||||
docker tag bitwarden/web:latest $REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
docker pull $_AZ_REGISTRY/web:latest
|
||||
else
|
||||
docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web:$_RELEASE_VERSION
|
||||
docker pull $_AZ_REGISTRY/web:$_BRANCH_NAME
|
||||
fi
|
||||
|
||||
docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
- name: Tag version
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker tag $_AZ_REGISTRY/web:latest $_AZ_REGISTRY/web:dryrun
|
||||
docker tag $_AZ_REGISTRY/web:latest $_AZ_REGISTRY/web-sh:dryrun
|
||||
else
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web:$_RELEASE_VERSION
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web:latest
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web-sh:latest
|
||||
fi
|
||||
|
||||
- name: Push version
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
env:
|
||||
REGISTRY: bitwardenprod.azurecr.io
|
||||
run: |
|
||||
docker push $REGISTRY/web:$_RELEASE_VERSION
|
||||
|
||||
docker push $REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
|
||||
docker push $_AZ_REGISTRY/web:dryrun
|
||||
docker push $_AZ_REGISTRY/web-sh:dryrun
|
||||
else
|
||||
docker push $_AZ_REGISTRY/web:$_RELEASE_VERSION
|
||||
docker push $_AZ_REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
docker push $_AZ_REGISTRY/web:latest
|
||||
docker push $_AZ_REGISTRY/web-sh:latest
|
||||
fi
|
||||
|
||||
- name: Log out of Docker
|
||||
run: docker logout
|
||||
|
||||
|
||||
ghpages-deploy:
|
||||
name: Deploy to GitHub Pages
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- setup
|
||||
name: Create Deploy PR for GitHub Pages
|
||||
runs-on: ubuntu-22.04
|
||||
needs: setup
|
||||
env:
|
||||
_RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||
_TAG_VERSION: ${{ needs.setup.outputs.tag_version }}
|
||||
@ -191,7 +165,7 @@ jobs:
|
||||
- name: Unzip build asset
|
||||
working-directory: assets
|
||||
run: unzip web-*-cloud-COMMERCIAL.zip
|
||||
|
||||
|
||||
- name: Create new branch
|
||||
run: |
|
||||
cd ${{ github.workspace }}/ghpages-deployment
|
||||
@ -200,12 +174,12 @@ jobs:
|
||||
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
|
||||
git config --global url."https://".insteadOf ssh://
|
||||
git checkout -b ${_BRANCH}
|
||||
|
||||
|
||||
- name: Copy build files
|
||||
run: |
|
||||
rm -rf ${{ github.workspace }}/ghpages-deployment/*
|
||||
cp -Rf ${{ github.workspace }}/assets/build/* ghpages-deployment/
|
||||
|
||||
|
||||
- name: Commit and push changes
|
||||
working-directory: ghpages-deployment
|
||||
run: |
|
||||
@ -233,7 +207,7 @@ jobs:
|
||||
|
||||
release:
|
||||
name: Create GitHub Release
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- setup
|
||||
- self-host
|
||||
|
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@ -1,3 +1,9 @@
|
||||
{
|
||||
"cSpell.words": ["Csprng", "decryptable", "Popout", "Reprompt", "takeuntil"]
|
||||
"cSpell.words": ["Csprng", "decryptable", "Popout", "Reprompt", "takeuntil"],
|
||||
"search.exclude": {
|
||||
"**/locales/[^e]*/messages.json": true,
|
||||
"**/locales/*[^n]/messages.json": true,
|
||||
"**/_locales/[^e]*/messages.json": true,
|
||||
"**/_locales/*[^n]/messages.json": true
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bitwarden/browser",
|
||||
"version": "2023.7.1",
|
||||
"version": "2023.8.0",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"build:mv3": "cross-env MANIFEST_VERSION=3 webpack",
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "استعادة العنصر"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "هل أنت متأكد من أنك تريد استعادة هذا العنصر؟"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "تم استعادة العنصر"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Elementi bərpa et"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Elementi bərpa etmək istədiyinizə əminsiniz?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Element bərpa edildi"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Аднавіць элемент"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Вы сапраўды хочаце аднавіць гэты элемент?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Элемент адноўлены"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Възстановяване на запис"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Сигурни ли сте, че искате да възстановите записа?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Записът е възстановен"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "বস্তু পুনরুদ্ধার"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "আপনি কি নিশ্চিত যে আপনি এই বস্তুটি পুনরুদ্ধার করতে চান?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "বস্তু পুনরুদ্ধারকৃত"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restaura l'element"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Esteu segur que voleu restaurar aquest element?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Element restaurat"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Obnovit položku"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Opravdu chcete tuto položku obnovit?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Položka byla obnovena"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Adfer yr eitem"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Gendan element"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Er du sikker på, at du vil gendanne dette element?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Element gendannet"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Eintrag wiederherstellen"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Soll dieser Eintrag wirklich wiederhergestellt werden?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Eintrag wiederhergestellt"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Ανάκτηση Στοιχείου"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Είστε βέβαιοι ότι θέλετε να ανακτήσετε αυτό το στοιχείο;"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Στοιχείο που έχει Ανακτηθεί"
|
||||
},
|
||||
|
@ -338,6 +338,9 @@
|
||||
"other": {
|
||||
"message": "Other"
|
||||
},
|
||||
"unlockMethodNeededToChangeTimeoutActionDesc": {
|
||||
"message": "Set up an unlock method to change your vault timeout action."
|
||||
},
|
||||
"rateExtension": {
|
||||
"message": "Rate the extension"
|
||||
},
|
||||
@ -1449,9 +1452,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
@ -1608,6 +1608,12 @@
|
||||
"biometricsNotSupportedDesc": {
|
||||
"message": "Browser biometrics is not supported on this device."
|
||||
},
|
||||
"biometricsFailedTitle": {
|
||||
"message": "Biometrics failed"
|
||||
},
|
||||
"biometricsFailedDesc": {
|
||||
"message": "Biometrics cannot be completed, consider using a master password or logging out. If this persists, please contact Bitwarden support."
|
||||
},
|
||||
"nativeMessaginPermissionErrorTitle": {
|
||||
"message": "Permission not provided"
|
||||
},
|
||||
@ -2158,8 +2164,8 @@
|
||||
"notificationSentDevice": {
|
||||
"message": "A notification has been sent to your device."
|
||||
},
|
||||
"logInInitiated": {
|
||||
"message": "Log in initiated"
|
||||
"loginInitiated": {
|
||||
"message": "Login initiated"
|
||||
},
|
||||
"exposedMasterPassword": {
|
||||
"message": "Exposed Master Password"
|
||||
@ -2245,6 +2251,31 @@
|
||||
"opensInANewWindow": {
|
||||
"message": "Opens in a new window"
|
||||
},
|
||||
"deviceApprovalRequired": {
|
||||
"message": "Device approval required. Select an approval option below:"
|
||||
},
|
||||
"rememberThisDevice": {
|
||||
"message": "Remember this device"
|
||||
},
|
||||
"uncheckIfPublicDevice": {
|
||||
"message": "Uncheck if using a public device"
|
||||
},
|
||||
"approveFromYourOtherDevice": {
|
||||
"message": "Approve from your other device"
|
||||
},
|
||||
"requestAdminApproval": {
|
||||
"message": "Request admin approval"
|
||||
},
|
||||
"approveWithMasterPassword": {
|
||||
"message": "Approve with master password"
|
||||
},
|
||||
"ssoIdentifierRequired": {
|
||||
"message": "Organization SSO identifier is required."
|
||||
},
|
||||
"eu": {
|
||||
"message": "EU",
|
||||
"description": "European Union"
|
||||
},
|
||||
"usDomain": {
|
||||
"message": "bitwarden.com"
|
||||
},
|
||||
@ -2260,6 +2291,134 @@
|
||||
"display": {
|
||||
"message": "Display"
|
||||
},
|
||||
"accountSuccessfullyCreated": {
|
||||
"message": "Account successfully created!"
|
||||
},
|
||||
"adminApprovalRequested": {
|
||||
"message": "Admin approval requested"
|
||||
},
|
||||
"adminApprovalRequestSentToAdmins": {
|
||||
"message": "Your request has been sent to your admin."
|
||||
},
|
||||
"youWillBeNotifiedOnceApproved": {
|
||||
"message": "You will be notified once approved."
|
||||
},
|
||||
"troubleLoggingIn": {
|
||||
"message": "Trouble logging in?"
|
||||
},
|
||||
"loginApproved": {
|
||||
"message": "Login approved"
|
||||
},
|
||||
"userEmailMissing": {
|
||||
"message": "User email missing"
|
||||
},
|
||||
"deviceTrusted": {
|
||||
"message": "Device trusted"
|
||||
},
|
||||
"inputRequired": {
|
||||
"message": "Input is required."
|
||||
},
|
||||
"required": {
|
||||
"message": "required"
|
||||
},
|
||||
"search": {
|
||||
"message": "Search"
|
||||
},
|
||||
"inputMinLength": {
|
||||
"message": "Input must be at least $COUNT$ characters long.",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"content": "$1",
|
||||
"example": "8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputMaxLength": {
|
||||
"message": "Input must not exceed $COUNT$ characters in length.",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"content": "$1",
|
||||
"example": "20"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputForbiddenCharacters": {
|
||||
"message": "The following characters are not allowed: $CHARACTERS$",
|
||||
"placeholders": {
|
||||
"characters": {
|
||||
"content": "$1",
|
||||
"example": "@, #, $, %"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputMinValue": {
|
||||
"message": "Input value must be at least $MIN$.",
|
||||
"placeholders": {
|
||||
"min": {
|
||||
"content": "$1",
|
||||
"example": "8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputMaxValue": {
|
||||
"message": "Input value must not exceed $MAX$.",
|
||||
"placeholders": {
|
||||
"max": {
|
||||
"content": "$1",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"multipleInputEmails": {
|
||||
"message": "1 or more emails are invalid"
|
||||
},
|
||||
"inputTrimValidator": {
|
||||
"message": "Input must not contain only whitespace.",
|
||||
"description": "Notification to inform the user that a form's input can't contain only whitespace."
|
||||
},
|
||||
"inputEmail": {
|
||||
"message": "Input is not an email address."
|
||||
},
|
||||
"fieldsNeedAttention": {
|
||||
"message": "$COUNT$ field(s) above need your attention.",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"content": "$1",
|
||||
"example": "4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"selectPlaceholder": {
|
||||
"message": "-- Select --"
|
||||
},
|
||||
"multiSelectPlaceholder": {
|
||||
"message": "-- Type to filter --"
|
||||
},
|
||||
"multiSelectLoading": {
|
||||
"message": "Retrieving options..."
|
||||
},
|
||||
"multiSelectNotFound": {
|
||||
"message": "No items found"
|
||||
},
|
||||
"multiSelectClearAll": {
|
||||
"message": "Clear all"
|
||||
},
|
||||
"plusNMore": {
|
||||
"message": "+ $QUANTITY$ more",
|
||||
"placeholders": {
|
||||
"quantity": {
|
||||
"content": "$1",
|
||||
"example": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"submenu": {
|
||||
"message": "Submenu"
|
||||
},
|
||||
"toggleCollapse": {
|
||||
"message": "Toggle collapse",
|
||||
"description": "Toggling an expand/collapse state."
|
||||
},
|
||||
"loginPasskey": {
|
||||
"message": "This login uses a passkey"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Restored item"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restaurar elemento"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "¿Estás seguro de que quieres restaurar este elemento?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Elemento restaurado"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Taasta kirje"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Oled kindel, et soovid selle kirje taastada?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Kirje on taastatud"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Berreskuratu elementua"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Ziur zaude elementu hau berreskuratu nahi duzula?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Elementua berreskuratua"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "بازیابی مورد"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "آیا مطمئن هستید که میخواهید این مورد را بازیابی کنید؟"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "مورد بازیابی شد"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Palauta kohde"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Haluatko varmasti palauttaa kohteen?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Kohde palautettiin"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Ibalik ang item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Sigurado ka bang nais mong ibalik ang item na ito?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item na nai-restore"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restaurer l'élément"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Êtes-vous sûr de vouloir restaurer cet élément ?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Élément restauré"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "שחזר פריט"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "האם אתה בטוח שברצונך לשחזר פריט זה?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "פריט ששוחזר"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "आइटम बहाल करें"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "क्या आप सुनिश्चित हैं कि आप इस आइटम को बहाल करना चाहते हैं?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "बहाल आइटम"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Vrati stavku"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Sigurno želiš vratiti ovu stavku?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Stavka vraćena"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Elem visszaállítása"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Biztosan visszaállításra kerüljön ezt az elem?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Visszaállított elem"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Pulihkan Item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Apakah Anda yakin ingin memulihkan item ini?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item Yang Dipulihkan"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Ripristina elemento"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Sei sicuro di voler ripristinare questo elemento?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Elemento ripristinato"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "アイテムをリストア"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "このアイテムをリストアしますか?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "リストアされたアイテム"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "ಐಟಂ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "ಈ ಐಟಂ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "ಐಟಂ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲಾಗಿದೆ"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "항목 복원"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "정말 이 항목을 복원하시겠습니까?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "복원된 항목"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Atkurti elementą"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Elementas atkurtas"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Atjaunot vienumu"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Jūs tiešām atjaunot šo vienumu?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Vienums atjaunots"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "ഇനം വീണ്ടെടുക്കുക "
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "ഈ ഇനം വീണ്ടെടുക്കണമെന്ന് ഉറപ്പാണോ?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "വീണ്ടെടുത്ത ഇനം"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Gjenopprett objekt"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Er du sikker på at du vil gjenopprette dette elementet?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Gjenopprettet objekt"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Item herstellen"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Weet je zeker dat je dit item wilt herstellen?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Hersteld item"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Przywróć element"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Czy na pewno chcesz przywrócić ten element?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Element został przywrócony"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restaurar Item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Você tem certeza que deseja restaurar esse item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item Restaurado"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restaurar item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Tem a certeza de que pretende restaurar este item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restaurado"
|
||||
},
|
||||
@ -2129,7 +2126,7 @@
|
||||
"message": "Iniciar sessão com o dispositivo"
|
||||
},
|
||||
"loginWithDeviceEnabledInfo": {
|
||||
"message": "O início de sessão com o dispositivo deve ser ativado nas definições da aplicação Bitwarden. Necessita de outra opção?"
|
||||
"message": "O início de sessão com o dispositivo deve ser ativado nas definições da aplicação Bitwarden. Precisa de outra opção?"
|
||||
},
|
||||
"fingerprintPhraseHeader": {
|
||||
"message": "Frase de impressão digital"
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restabilire articol"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Sigur doriți să restabiliți acest articol?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Articol restabilit"
|
||||
},
|
||||
|
@ -631,7 +631,7 @@
|
||||
"message": "Обновить"
|
||||
},
|
||||
"notificationUnlockDesc": {
|
||||
"message": "Разблокируйте свое хранилище Bitwarden для завершения запроса автозаполнения."
|
||||
"message": "Разблокируйте свое хранилище Bitwarden чтобы выполнить автозаполнение."
|
||||
},
|
||||
"notificationUnlock": {
|
||||
"message": "Разблокировать"
|
||||
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Восстановить элемент"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Вы уверены, что хотите восстановить этот элемент?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Элемент восстановлен"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "අයිතමය යළි පිහිටුවන්න"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "ඔබට මෙම අයිතමය යථා තත්වයට පත් කිරීමට අවශ්ය බව ඔබට විශ්වාසද?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "ප්රතිෂ්ඨාපනය අයිතමය"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Obnoviť položku"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Naozaj chcete obnoviť túto položku?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Obnovená položka"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Obnovi element"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Ste prepričani, da želite obnoviti ta element?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Element obnovljen"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Врати ставку"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Да ли сте сигурни да желите да вратите ову ставку?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Ставка враћена"
|
||||
},
|
||||
|
@ -11,7 +11,7 @@
|
||||
"description": "Extension description"
|
||||
},
|
||||
"loginOrCreateNewAccount": {
|
||||
"message": "Logga in eller skapa ett nytt konto för att komma åt dina lösenord."
|
||||
"message": "Logga in eller skapa ett nytt konto för att komma åt ditt säkra valv."
|
||||
},
|
||||
"createAccount": {
|
||||
"message": "Skapa konto"
|
||||
@ -342,7 +342,7 @@
|
||||
"message": "Betygsätt tillägget"
|
||||
},
|
||||
"rateExtensionDesc": {
|
||||
"message": "Överväg gärna att hjälpa oss genom att ge oss en bra recension!"
|
||||
"message": "Överväg gärna att skriva en recension om oss!"
|
||||
},
|
||||
"browserNotSupportClipboard": {
|
||||
"message": "Din webbläsare har inte stöd för att enkelt kopiera till urklipp. Kopiera till urklipp manuellt istället."
|
||||
@ -370,7 +370,7 @@
|
||||
}
|
||||
},
|
||||
"invalidMasterPassword": {
|
||||
"message": "Felaktigt huvudlösenord"
|
||||
"message": "Ogiltigt huvudlösenord"
|
||||
},
|
||||
"vaultTimeout": {
|
||||
"message": "Valvets tidsgräns"
|
||||
@ -736,7 +736,7 @@
|
||||
"message": "Kopiera verifieringskod"
|
||||
},
|
||||
"attachments": {
|
||||
"message": "Bifogade filer"
|
||||
"message": "Bilagor"
|
||||
},
|
||||
"deleteAttachment": {
|
||||
"message": "Radera bilaga"
|
||||
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Återställ objekt"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Är du säker på att du vill återställa detta objekt?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Återställde objekt"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Restore item"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Are you sure you want to restore this item?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Item restored"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "กู้คืนรายการ"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "คุณแน่ใจหรือไม่ว่าต้องการกู้คืนรายการนี้"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "คืนค่ารายการแล้ว"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Kaydı geri yükle"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Bu kaydı geri yüklemek istediğinizden emin misiniz?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Kayıt geri yüklendi"
|
||||
},
|
||||
|
@ -631,10 +631,10 @@
|
||||
"message": "Оновити"
|
||||
},
|
||||
"notificationUnlockDesc": {
|
||||
"message": "Unlock your Bitwarden vault to complete the auto-fill request."
|
||||
"message": "Розблокуйте своє сховище Bitwarden, щоб завершити запит автозаповнення."
|
||||
},
|
||||
"notificationUnlock": {
|
||||
"message": "Unlock"
|
||||
"message": "Розблокувати"
|
||||
},
|
||||
"enableContextMenuItem": {
|
||||
"message": "Показувати в контекстному меню"
|
||||
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Відновити запис"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Ви дійсно хочете відновити цей запис?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Запис відновлено"
|
||||
},
|
||||
@ -2228,7 +2225,7 @@
|
||||
}
|
||||
},
|
||||
"loggingInOn": {
|
||||
"message": "Logging in on"
|
||||
"message": "Увійти на"
|
||||
},
|
||||
"opensInANewWindow": {
|
||||
"message": "Відкривається у новому вікні"
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "Khôi phục mục"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "Bạn có chắc chắn muốn khôi phục mục này không?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "Mục đã được khôi phục"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "恢复项目"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "您确定要恢复此项目吗?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "项目已恢复"
|
||||
},
|
||||
|
@ -1446,9 +1446,6 @@
|
||||
"restoreItem": {
|
||||
"message": "還原項目"
|
||||
},
|
||||
"restoreItemConfirmation": {
|
||||
"message": "您確定要還原此項目嗎?"
|
||||
},
|
||||
"restoredItem": {
|
||||
"message": "項目已還原"
|
||||
},
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction";
|
||||
import { AuthRequestCryptoServiceImplementation } from "@bitwarden/common/auth/services/auth-request-crypto.service.implementation";
|
||||
|
||||
import {
|
||||
CryptoServiceInitOptions,
|
||||
cryptoServiceFactory,
|
||||
} from "../../../platform/background/service-factories/crypto-service.factory";
|
||||
import {
|
||||
CachedServices,
|
||||
FactoryOptions,
|
||||
factory,
|
||||
} from "../../../platform/background/service-factories/factory-options";
|
||||
|
||||
type AuthRequestCryptoServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type AuthRequestCryptoServiceInitOptions = AuthRequestCryptoServiceFactoryOptions &
|
||||
CryptoServiceInitOptions;
|
||||
|
||||
export function authRequestCryptoServiceFactory(
|
||||
cache: { authRequestCryptoService?: AuthRequestCryptoServiceAbstraction } & CachedServices,
|
||||
opts: AuthRequestCryptoServiceInitOptions
|
||||
): Promise<AuthRequestCryptoServiceAbstraction> {
|
||||
return factory(
|
||||
cache,
|
||||
"authRequestCryptoService",
|
||||
opts,
|
||||
async () => new AuthRequestCryptoServiceImplementation(await cryptoServiceFactory(cache, opts))
|
||||
);
|
||||
}
|
@ -52,6 +52,14 @@ import {
|
||||
PasswordStrengthServiceInitOptions,
|
||||
} from "../../../tools/background/service_factories/password-strength-service.factory";
|
||||
|
||||
import {
|
||||
authRequestCryptoServiceFactory,
|
||||
AuthRequestCryptoServiceInitOptions,
|
||||
} from "./auth-request-crypto-service.factory";
|
||||
import {
|
||||
deviceTrustCryptoServiceFactory,
|
||||
DeviceTrustCryptoServiceInitOptions,
|
||||
} from "./device-trust-crypto-service.factory";
|
||||
import {
|
||||
keyConnectorServiceFactory,
|
||||
KeyConnectorServiceInitOptions,
|
||||
@ -75,7 +83,9 @@ export type AuthServiceInitOptions = AuthServiceFactoyOptions &
|
||||
I18nServiceInitOptions &
|
||||
EncryptServiceInitOptions &
|
||||
PolicyServiceInitOptions &
|
||||
PasswordStrengthServiceInitOptions;
|
||||
PasswordStrengthServiceInitOptions &
|
||||
DeviceTrustCryptoServiceInitOptions &
|
||||
AuthRequestCryptoServiceInitOptions;
|
||||
|
||||
export function authServiceFactory(
|
||||
cache: { authService?: AbstractAuthService } & CachedServices,
|
||||
@ -101,7 +111,9 @@ export function authServiceFactory(
|
||||
await i18nServiceFactory(cache, opts),
|
||||
await encryptServiceFactory(cache, opts),
|
||||
await passwordStrengthServiceFactory(cache, opts),
|
||||
await policyServiceFactory(cache, opts)
|
||||
await policyServiceFactory(cache, opts),
|
||||
await deviceTrustCryptoServiceFactory(cache, opts),
|
||||
await authRequestCryptoServiceFactory(cache, opts)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||
import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device-trust-crypto.service.implementation";
|
||||
|
||||
import {
|
||||
DevicesApiServiceInitOptions,
|
||||
devicesApiServiceFactory,
|
||||
} from "../../../background/service-factories/devices-api-service.factory";
|
||||
import {
|
||||
AppIdServiceInitOptions,
|
||||
appIdServiceFactory,
|
||||
} from "../../../platform/background/service-factories/app-id-service.factory";
|
||||
import {
|
||||
CryptoFunctionServiceInitOptions,
|
||||
cryptoFunctionServiceFactory,
|
||||
} from "../../../platform/background/service-factories/crypto-function-service.factory";
|
||||
import {
|
||||
CryptoServiceInitOptions,
|
||||
cryptoServiceFactory,
|
||||
} from "../../../platform/background/service-factories/crypto-service.factory";
|
||||
import {
|
||||
EncryptServiceInitOptions,
|
||||
encryptServiceFactory,
|
||||
} from "../../../platform/background/service-factories/encrypt-service.factory";
|
||||
import {
|
||||
CachedServices,
|
||||
FactoryOptions,
|
||||
factory,
|
||||
} from "../../../platform/background/service-factories/factory-options";
|
||||
import {
|
||||
I18nServiceInitOptions,
|
||||
i18nServiceFactory,
|
||||
} from "../../../platform/background/service-factories/i18n-service.factory";
|
||||
import {
|
||||
PlatformUtilsServiceInitOptions,
|
||||
platformUtilsServiceFactory,
|
||||
} from "../../../platform/background/service-factories/platform-utils-service.factory";
|
||||
import {
|
||||
StateServiceInitOptions,
|
||||
stateServiceFactory,
|
||||
} from "../../../platform/background/service-factories/state-service.factory";
|
||||
|
||||
type DeviceTrustCryptoServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactoryOptions &
|
||||
CryptoFunctionServiceInitOptions &
|
||||
CryptoServiceInitOptions &
|
||||
EncryptServiceInitOptions &
|
||||
StateServiceInitOptions &
|
||||
AppIdServiceInitOptions &
|
||||
DevicesApiServiceInitOptions &
|
||||
I18nServiceInitOptions &
|
||||
PlatformUtilsServiceInitOptions;
|
||||
|
||||
export function deviceTrustCryptoServiceFactory(
|
||||
cache: { deviceTrustCryptoService?: DeviceTrustCryptoServiceAbstraction } & CachedServices,
|
||||
opts: DeviceTrustCryptoServiceInitOptions
|
||||
): Promise<DeviceTrustCryptoServiceAbstraction> {
|
||||
return factory(
|
||||
cache,
|
||||
"deviceTrustCryptoService",
|
||||
opts,
|
||||
async () =>
|
||||
new DeviceTrustCryptoService(
|
||||
await cryptoFunctionServiceFactory(cache, opts),
|
||||
await cryptoServiceFactory(cache, opts),
|
||||
await encryptServiceFactory(cache, opts),
|
||||
await stateServiceFactory(cache, opts),
|
||||
await appIdServiceFactory(cache, opts),
|
||||
await devicesApiServiceFactory(cache, opts),
|
||||
await i18nServiceFactory(cache, opts),
|
||||
await platformUtilsServiceFactory(cache, opts)
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction";
|
||||
import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service";
|
||||
|
||||
import {
|
||||
ApiServiceInitOptions,
|
||||
apiServiceFactory,
|
||||
} from "../../../platform/background/service-factories/api-service.factory";
|
||||
import {
|
||||
FactoryOptions,
|
||||
CachedServices,
|
||||
factory,
|
||||
} from "../../../platform/background/service-factories/factory-options";
|
||||
|
||||
type UserVerificationApiServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type UserVerificationApiServiceInitOptions = UserVerificationApiServiceFactoryOptions &
|
||||
ApiServiceInitOptions;
|
||||
|
||||
export function userVerificationApiServiceFactory(
|
||||
cache: { userVerificationApiService?: UserVerificationApiServiceAbstraction } & CachedServices,
|
||||
opts: UserVerificationApiServiceInitOptions
|
||||
): Promise<UserVerificationApiServiceAbstraction> {
|
||||
return factory(
|
||||
cache,
|
||||
"userVerificationApiService",
|
||||
opts,
|
||||
async () => new UserVerificationApiService(await apiServiceFactory(cache, opts))
|
||||
);
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import { UserVerificationService as AbstractUserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service";
|
||||
|
||||
import {
|
||||
CryptoServiceInitOptions,
|
||||
cryptoServiceFactory,
|
||||
} from "../../../platform/background/service-factories/crypto-service.factory";
|
||||
import {
|
||||
FactoryOptions,
|
||||
CachedServices,
|
||||
factory,
|
||||
} from "../../../platform/background/service-factories/factory-options";
|
||||
import {
|
||||
I18nServiceInitOptions,
|
||||
i18nServiceFactory,
|
||||
} from "../../../platform/background/service-factories/i18n-service.factory";
|
||||
import {
|
||||
StateServiceInitOptions,
|
||||
stateServiceFactory,
|
||||
} from "../../../platform/background/service-factories/state-service.factory";
|
||||
|
||||
import {
|
||||
UserVerificationApiServiceInitOptions,
|
||||
userVerificationApiServiceFactory,
|
||||
} from "./user-verification-api-service.factory";
|
||||
|
||||
type UserVerificationServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryOptions &
|
||||
StateServiceInitOptions &
|
||||
CryptoServiceInitOptions &
|
||||
I18nServiceInitOptions &
|
||||
UserVerificationApiServiceInitOptions;
|
||||
|
||||
export function userVerificationServiceFactory(
|
||||
cache: { userVerificationService?: AbstractUserVerificationService } & CachedServices,
|
||||
opts: UserVerificationServiceInitOptions
|
||||
): Promise<AbstractUserVerificationService> {
|
||||
return factory(
|
||||
cache,
|
||||
"userVerificationService",
|
||||
opts,
|
||||
async () =>
|
||||
new UserVerificationService(
|
||||
await stateServiceFactory(cache, opts),
|
||||
await cryptoServiceFactory(cache, opts),
|
||||
await i18nServiceFactory(cache, opts),
|
||||
await userVerificationApiServiceFactory(cache, opts)
|
||||
)
|
||||
);
|
||||
}
|
@ -5,14 +5,20 @@
|
||||
<span class="title">{{ "verifyIdentity" | i18n }}</span>
|
||||
</h1>
|
||||
<div class="right">
|
||||
<button type="submit" *ngIf="!hideInput">{{ "unlock" | i18n }}</button>
|
||||
<button type="submit" *ngIf="pinEnabled || masterPasswordEnabled">
|
||||
{{ "unlock" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main tabindex="-1">
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-flex" appBoxRow *ngIf="!hideInput">
|
||||
<div class="row-main" *ngIf="pinLock">
|
||||
<div
|
||||
class="box-content-row box-content-row-flex"
|
||||
appBoxRow
|
||||
*ngIf="pinEnabled || masterPasswordEnabled"
|
||||
>
|
||||
<div class="row-main" *ngIf="pinEnabled">
|
||||
<label for="pin">{{ "pin" | i18n }}</label>
|
||||
<input
|
||||
id="pin"
|
||||
@ -24,7 +30,7 @@
|
||||
appInputVerbatim
|
||||
/>
|
||||
</div>
|
||||
<div class="row-main" *ngIf="!pinLock">
|
||||
<div class="row-main" *ngIf="masterPasswordEnabled && !pinEnabled">
|
||||
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
|
||||
<input
|
||||
id="masterPassword"
|
||||
|
@ -2,14 +2,14 @@ import { Component, NgZone } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
@ -19,6 +19,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors";
|
||||
|
||||
@ -44,14 +45,15 @@ export class LockComponent extends BaseLockComponent {
|
||||
stateService: StateService,
|
||||
apiService: ApiService,
|
||||
logService: LogService,
|
||||
keyConnectorService: KeyConnectorService,
|
||||
ngZone: NgZone,
|
||||
policyApiService: PolicyApiServiceAbstraction,
|
||||
policyService: InternalPolicyService,
|
||||
passwordStrengthService: PasswordStrengthServiceAbstraction,
|
||||
private authService: AuthService,
|
||||
route: ActivatedRoute,
|
||||
dialogService: DialogServiceAbstraction
|
||||
dialogService: DialogService,
|
||||
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||
userVerificationService: UserVerificationService
|
||||
) {
|
||||
super(
|
||||
router,
|
||||
@ -65,13 +67,14 @@ export class LockComponent extends BaseLockComponent {
|
||||
stateService,
|
||||
apiService,
|
||||
logService,
|
||||
keyConnectorService,
|
||||
ngZone,
|
||||
policyApiService,
|
||||
policyService,
|
||||
passwordStrengthService,
|
||||
route,
|
||||
dialogService
|
||||
dialogService,
|
||||
deviceTrustCryptoService,
|
||||
userVerificationService
|
||||
);
|
||||
this.successRoute = "/tabs/current";
|
||||
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
|
||||
@ -83,7 +86,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
(await this.stateService.getDisableAutoBiometricsPrompt()) ?? true;
|
||||
|
||||
window.setTimeout(async () => {
|
||||
document.getElementById(this.pinLock ? "pin" : "masterPassword").focus();
|
||||
document.getElementById(this.pinEnabled ? "pin" : "masterPassword")?.focus();
|
||||
if (
|
||||
this.biometricLock &&
|
||||
!disableAutoBiometricsPrompt &&
|
||||
@ -95,7 +98,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
}, 100);
|
||||
}
|
||||
|
||||
async unlockBiometric(): Promise<boolean> {
|
||||
override async unlockBiometric(): Promise<boolean> {
|
||||
if (!this.biometricLock) {
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
<div id="login-initiated">
|
||||
<header>
|
||||
<h1 class="margin-auto">
|
||||
<span class="title">{{ "loginInitiated" | i18n }}</span>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<div class="content login-page">
|
||||
<div class="full-loading-spinner" *ngIf="loading">
|
||||
<i class="bwi bwi-spinner bwi-spin bwi-3x" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!loading">
|
||||
<ng-container *ngIf="data.state == State.ExistingUserUntrustedDevice">
|
||||
<div class="standard-x-margin">
|
||||
<p class="lead">{{ "loginInitiated" | i18n }}</p>
|
||||
<h6 class="mb-20px">{{ "deviceApprovalRequired" | i18n }}</h6>
|
||||
</div>
|
||||
|
||||
<form
|
||||
id="rememberDeviceForm"
|
||||
class="mb-20px standard-x-margin"
|
||||
[formGroup]="rememberDeviceForm"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="rememberDevice"
|
||||
name="rememberDevice"
|
||||
formControlName="rememberDevice"
|
||||
/>
|
||||
<label for="rememberDevice">
|
||||
{{ "rememberThisDevice" | i18n }}
|
||||
</label>
|
||||
<p id="rememberThisDeviceHintText">{{ "uncheckIfPublicDevice" | i18n }}</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="box mb-20px">
|
||||
<button
|
||||
*ngIf="data.showApproveFromOtherDeviceBtn"
|
||||
(click)="approveFromOtherDevice()"
|
||||
type="button"
|
||||
class="btn primary block"
|
||||
>
|
||||
<b>{{ "approveFromYourOtherDevice" | i18n }}</b>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="data.showReqAdminApprovalBtn"
|
||||
(click)="requestAdminApproval()"
|
||||
type="button"
|
||||
class="btn block btn-top-margin"
|
||||
>
|
||||
{{ "requestAdminApproval" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="data.showApproveWithMasterPasswordBtn"
|
||||
type="button"
|
||||
class="btn block btn-top-margin"
|
||||
(click)="approveWithMasterPassword()"
|
||||
>
|
||||
{{ "approveWithMasterPassword" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="data.state == State.NewUser">
|
||||
<div class="standard-x-margin">
|
||||
<p class="lead">{{ "loginInitiated" | i18n }}</p>
|
||||
</div>
|
||||
|
||||
<form
|
||||
id="rememberDeviceForm"
|
||||
class="mb-20px standard-x-margin"
|
||||
[formGroup]="rememberDeviceForm"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="rememberDevice"
|
||||
name="rememberDevice"
|
||||
formControlName="rememberDevice"
|
||||
/>
|
||||
<label for="rememberDevice">
|
||||
{{ "rememberThisDevice" | i18n }}
|
||||
</label>
|
||||
<p id="rememberThisDeviceHintText">{{ "uncheckIfPublicDevice" | i18n }}</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="box mb-20px">
|
||||
<button (click)="createUser()" type="button" class="btn primary block">
|
||||
<b>{{ "continue" | i18n }}</b>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<hr class="muted-hr mx-5px mb-20px" />
|
||||
|
||||
<div class="small mx-5px">
|
||||
<p class="no-margin">{{ "loggingInAs" | i18n }} {{ data.userEmail }}</p>
|
||||
<a tabindex="0" role="button" style="cursor: pointer" (click)="logOut()">{{
|
||||
"notYou" | i18n
|
||||
}}</a>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,18 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { BaseLoginDecryptionOptionsComponent } from "@bitwarden/angular/auth/components/base-login-decryption-options.component";
|
||||
|
||||
@Component({
|
||||
selector: "browser-login-decryption-options",
|
||||
templateUrl: "login-decryption-options.component.html",
|
||||
})
|
||||
export class LoginDecryptionOptionsComponent extends BaseLoginDecryptionOptionsComponent {
|
||||
override async createUser(): Promise<void> {
|
||||
try {
|
||||
await super.createUser();
|
||||
await this.router.navigate(["/tabs/vault"]);
|
||||
} catch (error) {
|
||||
this.validationService.showError(error);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,32 +5,57 @@
|
||||
</h1>
|
||||
</header>
|
||||
<div class="content login-page">
|
||||
<div>
|
||||
<p class="lead">{{ "logInInitiated" | i18n }}</p>
|
||||
|
||||
<ng-container *ngIf="state == StateEnum.StandardAuthRequest">
|
||||
<div>
|
||||
<p>{{ "notificationSentDevice" | i18n }}</p>
|
||||
<p class="lead">{{ "loginInitiated" | i18n }}</p>
|
||||
|
||||
<p>
|
||||
{{ "fingerprintMatchInfo" | i18n }}
|
||||
</p>
|
||||
<div>
|
||||
<p>{{ "notificationSentDevice" | i18n }}</p>
|
||||
|
||||
<p>
|
||||
{{ "fingerprintMatchInfo" | i18n }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<b class="fingerprint-phrase-header">{{ "fingerprintPhraseHeader" | i18n }}</b>
|
||||
<p class="fingerprint-text">
|
||||
<code>{{ fingerprintPhrase }}</code>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="resend-notification" *ngIf="showResendNotification">
|
||||
<a (click)="startPasswordlessLogin()">{{ "resendNotification" | i18n }}</a>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
{{ "loginWithDeviceEnabledInfo" | i18n }}
|
||||
<a href="#" (click)="back()">{{ "viewAllLoginOptions" | i18n }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="state == StateEnum.AdminAuthRequest">
|
||||
<div>
|
||||
<b class="fingerprint-phrase-header">{{ "fingerprintPhraseHeader" | i18n }}</b>
|
||||
<p class="fingerprint-text">
|
||||
<code>{{ fingerprintPhrase }}</code>
|
||||
</p>
|
||||
</div>
|
||||
<p class="lead">{{ "adminApprovalRequested" | i18n }}</p>
|
||||
|
||||
<div class="resend-notification" *ngIf="showResendNotification">
|
||||
<a (click)="startPasswordlessLogin()">{{ "resendNotification" | i18n }}</a>
|
||||
</div>
|
||||
<div>
|
||||
<p>{{ "adminApprovalRequestSentToAdmins" | i18n }}</p>
|
||||
<p>{{ "youWillBeNotifiedOnceApproved" | i18n }}</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
{{ "loginWithDeviceEnabledInfo" | i18n }}
|
||||
<a routerLink="/login">{{ "viewAllLoginOptions" | i18n }}</a>
|
||||
<div>
|
||||
<b class="fingerprint-phrase-header">{{ "fingerprintPhraseHeader" | i18n }}</b>
|
||||
<p class="fingerprint-text">
|
||||
<code>{{ fingerprintPhrase }}</code>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
{{ "troubleLoggingIn" | i18n }}
|
||||
<a routerLink="/login-initiated">{{ "viewAllLoginOptions" | i18n }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { Location } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { LoginWithDeviceComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-with-device.component";
|
||||
import { AnonymousHubService } from "@bitwarden/common/abstractions/anonymousHub.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
@ -42,7 +45,10 @@ export class LoginWithDeviceComponent
|
||||
validationService: ValidationService,
|
||||
stateService: StateService,
|
||||
loginService: LoginService,
|
||||
syncService: SyncService
|
||||
syncService: SyncService,
|
||||
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||
authReqCryptoService: AuthRequestCryptoServiceAbstraction,
|
||||
private location: Location
|
||||
) {
|
||||
super(
|
||||
router,
|
||||
@ -59,10 +65,16 @@ export class LoginWithDeviceComponent
|
||||
anonymousHubService,
|
||||
validationService,
|
||||
stateService,
|
||||
loginService
|
||||
loginService,
|
||||
deviceTrustCryptoService,
|
||||
authReqCryptoService
|
||||
);
|
||||
super.onSuccessfulLogin = async () => {
|
||||
await syncService.fullSync(true);
|
||||
};
|
||||
}
|
||||
|
||||
protected back() {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
|
@ -4,7 +4,6 @@ import { Router } from "@angular/router";
|
||||
|
||||
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
|
||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
@ -15,6 +14,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
selector: "app-register",
|
||||
@ -38,7 +38,7 @@ export class RegisterComponent extends BaseRegisterComponent {
|
||||
environmentService: EnvironmentService,
|
||||
logService: LogService,
|
||||
auditService: AuditService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
dialogService: DialogService
|
||||
) {
|
||||
super(
|
||||
formValidationErrorService,
|
||||
|
@ -1,2 +1 @@
|
||||
export { LockGuardService } from "./lock-guard.service";
|
||||
export { UnauthGuardService } from "./unauth-guard.service";
|
||||
|
@ -1,8 +0,0 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { LockGuard as BaseLockGuardService } from "@bitwarden/angular/auth/guards/lock.guard";
|
||||
|
||||
@Injectable()
|
||||
export class LockGuardService extends BaseLockGuardService {
|
||||
protected homepage = "tabs/current";
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards/unauth.guard";
|
||||
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards";
|
||||
|
||||
@Injectable()
|
||||
export class UnauthGuardService extends BaseUnauthGuardService {
|
||||
|
@ -2,7 +2,6 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/components/set-password.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
@ -15,6 +14,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
selector: "app-set-password",
|
||||
@ -36,7 +36,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
|
||||
route: ActivatedRoute,
|
||||
organizationApiService: OrganizationApiServiceAbstraction,
|
||||
organizationUserService: OrganizationUserService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
dialogService: DialogService
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@ -35,7 +36,8 @@ export class SsoComponent extends BaseSsoComponent {
|
||||
syncService: SyncService,
|
||||
environmentService: EnvironmentService,
|
||||
logService: LogService,
|
||||
private vaultTimeoutService: VaultTimeoutService
|
||||
configService: ConfigServiceAbstraction,
|
||||
@Inject(WINDOW) private win: Window
|
||||
) {
|
||||
super(
|
||||
authService,
|
||||
@ -48,7 +50,8 @@ export class SsoComponent extends BaseSsoComponent {
|
||||
cryptoFunctionService,
|
||||
environmentService,
|
||||
passwordGenerationService,
|
||||
logService
|
||||
logService,
|
||||
configService
|
||||
);
|
||||
|
||||
const url = this.environmentService.getWebVaultUrl();
|
||||
@ -57,15 +60,22 @@ export class SsoComponent extends BaseSsoComponent {
|
||||
this.clientId = "browser";
|
||||
|
||||
super.onSuccessfulLogin = async () => {
|
||||
await syncService.fullSync(true);
|
||||
syncService.fullSync(true);
|
||||
|
||||
// If the vault is unlocked then this will clear keys from memory, which we don't want to do
|
||||
if ((await this.authService.getAuthStatus()) !== AuthenticationStatus.Unlocked) {
|
||||
BrowserApi.reloadOpenWindows();
|
||||
}
|
||||
|
||||
const thisWindow = window.open("", "_self");
|
||||
thisWindow.close();
|
||||
this.win.close();
|
||||
};
|
||||
|
||||
super.onSuccessfulLoginTde = async () => {
|
||||
syncService.fullSync(true);
|
||||
};
|
||||
|
||||
super.onSuccessfulLoginTdeNavigate = async () => {
|
||||
this.win.close();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
|
||||
@ -11,6 +11,7 @@ import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@ -18,6 +19,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
import { PopupUtilsService } from "../../popup/services/popup-utils.service";
|
||||
@ -48,7 +50,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
twoFactorService: TwoFactorService,
|
||||
appIdService: AppIdService,
|
||||
loginService: LoginService,
|
||||
private dialogService: DialogServiceAbstraction
|
||||
configService: ConfigServiceAbstraction,
|
||||
private dialogService: DialogService,
|
||||
@Inject(WINDOW) protected win: Window
|
||||
) {
|
||||
super(
|
||||
authService,
|
||||
@ -56,19 +60,28 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
i18nService,
|
||||
apiService,
|
||||
platformUtilsService,
|
||||
window,
|
||||
win,
|
||||
environmentService,
|
||||
stateService,
|
||||
route,
|
||||
logService,
|
||||
twoFactorService,
|
||||
appIdService,
|
||||
loginService
|
||||
loginService,
|
||||
configService
|
||||
);
|
||||
super.onSuccessfulLogin = () => {
|
||||
this.loginService.clearValues();
|
||||
return syncService.fullSync(true);
|
||||
super.onSuccessfulLogin = async () => {
|
||||
syncService.fullSync(true);
|
||||
};
|
||||
|
||||
super.onSuccessfulLoginTde = async () => {
|
||||
syncService.fullSync(true);
|
||||
};
|
||||
|
||||
super.onSuccessfulLoginTdeNavigate = async () => {
|
||||
this.win.close();
|
||||
};
|
||||
|
||||
super.successRoute = "/tabs/vault";
|
||||
// FIXME: Chromium 110 has broken WebAuthn support in extensions via an iframe
|
||||
this.webAuthnNewTab = true;
|
||||
@ -107,7 +120,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "warning" },
|
||||
content: { key: "popup2faCloseMessage" },
|
||||
type: SimpleDialogType.WARNING,
|
||||
type: "warning",
|
||||
});
|
||||
if (confirmed) {
|
||||
this.popupUtilsService.popOut(window);
|
||||
@ -117,11 +130,11 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
|
||||
if (qParams.sso === "true") {
|
||||
super.onSuccessfulLogin = () => {
|
||||
super.onSuccessfulLogin = async () => {
|
||||
// This is not awaited so we don't pause the application while the sync is happening.
|
||||
// This call is executed by the service that lives in the background script so it will continue
|
||||
// the sync even if this tab closes.
|
||||
const syncPromise = this.syncService.fullSync(true);
|
||||
this.syncService.fullSync(true);
|
||||
|
||||
// Force sidebars (FF && Opera) to reload while exempting current window
|
||||
// because we are just going to close the current window.
|
||||
@ -130,8 +143,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
// We don't need this window anymore because the intent is for the user to be left
|
||||
// on the web vault screen which tells them to continue in the browser extension (sidebar or popup)
|
||||
BrowserApi.closeBitwardenExtensionTab();
|
||||
|
||||
return syncPromise;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -2,6 +2,10 @@ import {
|
||||
TotpServiceInitOptions,
|
||||
totpServiceFactory,
|
||||
} from "../../../auth/background/service-factories/totp-service.factory";
|
||||
import {
|
||||
UserVerificationServiceInitOptions,
|
||||
userVerificationServiceFactory,
|
||||
} from "../../../auth/background/service-factories/user-verification-service.factory";
|
||||
import {
|
||||
EventCollectionServiceInitOptions,
|
||||
eventCollectionServiceFactory,
|
||||
@ -38,7 +42,8 @@ export type AutoFillServiceInitOptions = AutoFillServiceOptions &
|
||||
TotpServiceInitOptions &
|
||||
EventCollectionServiceInitOptions &
|
||||
LogServiceInitOptions &
|
||||
SettingsServiceInitOptions;
|
||||
SettingsServiceInitOptions &
|
||||
UserVerificationServiceInitOptions;
|
||||
|
||||
export function autofillServiceFactory(
|
||||
cache: { autofillService?: AbstractAutoFillService } & CachedServices,
|
||||
@ -55,7 +60,8 @@ export function autofillServiceFactory(
|
||||
await totpServiceFactory(cache, opts),
|
||||
await eventCollectionServiceFactory(cache, opts),
|
||||
await logServiceFactory(cache, opts),
|
||||
await settingsServiceFactory(cache, opts)
|
||||
await settingsServiceFactory(cache, opts),
|
||||
await userVerificationServiceFactory(cache, opts)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
@ -13,6 +14,7 @@ describe("CipherContextMenuHandler", () => {
|
||||
let mainContextMenuHandler: MockProxy<MainContextMenuHandler>;
|
||||
let authService: MockProxy<AuthService>;
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let userVerificationService: MockProxy<UserVerificationService>;
|
||||
|
||||
let sut: CipherContextMenuHandler;
|
||||
|
||||
@ -20,10 +22,17 @@ describe("CipherContextMenuHandler", () => {
|
||||
mainContextMenuHandler = mock();
|
||||
authService = mock();
|
||||
cipherService = mock();
|
||||
userVerificationService = mock();
|
||||
userVerificationService.hasMasterPassword.mockResolvedValue(true);
|
||||
|
||||
jest.spyOn(MainContextMenuHandler, "removeAll").mockResolvedValue();
|
||||
|
||||
sut = new CipherContextMenuHandler(mainContextMenuHandler, authService, cipherService);
|
||||
sut = new CipherContextMenuHandler(
|
||||
mainContextMenuHandler,
|
||||
authService,
|
||||
cipherService,
|
||||
userVerificationService
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => jest.resetAllMocks());
|
||||
@ -83,11 +92,11 @@ describe("CipherContextMenuHandler", () => {
|
||||
};
|
||||
|
||||
cipherService.getAllDecryptedForUrl.mockResolvedValue([
|
||||
null,
|
||||
undefined,
|
||||
{ type: CipherType.Card },
|
||||
{ type: CipherType.Login, reprompt: CipherRepromptType.Password },
|
||||
realCipher,
|
||||
null, // invalid cipher
|
||||
undefined, // invalid cipher
|
||||
{ type: CipherType.Card }, // invalid cipher
|
||||
{ type: CipherType.Login, reprompt: CipherRepromptType.Password }, // invalid cipher
|
||||
realCipher, // valid cipher
|
||||
] as any[]);
|
||||
|
||||
await sut.update("https://test.com");
|
||||
@ -96,7 +105,7 @@ describe("CipherContextMenuHandler", () => {
|
||||
|
||||
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith("https://test.com");
|
||||
|
||||
expect(mainContextMenuHandler.loadOptions).toHaveBeenCalledTimes(1);
|
||||
expect(mainContextMenuHandler.loadOptions).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(mainContextMenuHandler.loadOptions).toHaveBeenCalledWith(
|
||||
"Test Cipher (Test Username)",
|
||||
@ -105,5 +114,61 @@ describe("CipherContextMenuHandler", () => {
|
||||
realCipher
|
||||
);
|
||||
});
|
||||
|
||||
it("adds ciphers with master password reprompt if the user does not have a master password", async () => {
|
||||
authService.getAuthStatus.mockResolvedValue(AuthenticationStatus.Unlocked);
|
||||
|
||||
// User does not have a master password, or has one but hasn't logged in with it (key connector user or TDE user)
|
||||
userVerificationService.hasMasterPasswordAndMasterKeyHash.mockResolvedValue(false);
|
||||
|
||||
mainContextMenuHandler.init.mockResolvedValue(true);
|
||||
|
||||
const realCipher = {
|
||||
id: "5",
|
||||
type: CipherType.Login,
|
||||
reprompt: CipherRepromptType.None,
|
||||
name: "Test Cipher",
|
||||
login: { username: "Test Username" },
|
||||
};
|
||||
|
||||
const repromptCipher = {
|
||||
id: "6",
|
||||
type: CipherType.Login,
|
||||
reprompt: CipherRepromptType.Password,
|
||||
name: "Test Reprompt Cipher",
|
||||
login: { username: "Test Username" },
|
||||
};
|
||||
|
||||
cipherService.getAllDecryptedForUrl.mockResolvedValue([
|
||||
null, // invalid cipher
|
||||
undefined, // invalid cipher
|
||||
{ type: CipherType.Card }, // invalid cipher
|
||||
repromptCipher, // valid cipher
|
||||
realCipher, // valid cipher
|
||||
] as any[]);
|
||||
|
||||
await sut.update("https://test.com");
|
||||
|
||||
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith("https://test.com");
|
||||
|
||||
// Should call this twice, once for each valid cipher
|
||||
expect(mainContextMenuHandler.loadOptions).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(mainContextMenuHandler.loadOptions).toHaveBeenCalledWith(
|
||||
"Test Cipher (Test Username)",
|
||||
"5",
|
||||
"https://test.com",
|
||||
realCipher
|
||||
);
|
||||
|
||||
expect(mainContextMenuHandler.loadOptions).toHaveBeenCalledWith(
|
||||
"Test Reprompt Cipher (Test Username)",
|
||||
"6",
|
||||
"https://test.com",
|
||||
repromptCipher
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
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 { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
authServiceFactory,
|
||||
AuthServiceInitOptions,
|
||||
} from "../../auth/background/service-factories/auth-service.factory";
|
||||
import { userVerificationServiceFactory } from "../../auth/background/service-factories/user-verification-service.factory";
|
||||
import { Account } from "../../models/account";
|
||||
import { CachedServices } from "../../platform/background/service-factories/factory-options";
|
||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
@ -38,7 +39,8 @@ export class CipherContextMenuHandler {
|
||||
constructor(
|
||||
private mainContextMenuHandler: MainContextMenuHandler,
|
||||
private authService: AuthService,
|
||||
private cipherService: CipherService
|
||||
private cipherService: CipherService,
|
||||
private userVerificationService: UserVerificationService
|
||||
) {}
|
||||
|
||||
static async create(cachedServices: CachedServices) {
|
||||
@ -77,7 +79,8 @@ export class CipherContextMenuHandler {
|
||||
return new CipherContextMenuHandler(
|
||||
await MainContextMenuHandler.mv3Create(cachedServices),
|
||||
await authServiceFactory(cachedServices, serviceOptions),
|
||||
await cipherServiceFactory(cachedServices, serviceOptions)
|
||||
await cipherServiceFactory(cachedServices, serviceOptions),
|
||||
await userVerificationServiceFactory(cachedServices, serviceOptions)
|
||||
);
|
||||
}
|
||||
|
||||
@ -180,7 +183,7 @@ export class CipherContextMenuHandler {
|
||||
if (
|
||||
cipher == null ||
|
||||
cipher.type !== CipherType.Login ||
|
||||
cipher.reprompt !== CipherRepromptType.None
|
||||
(await this.userVerificationService.hasMasterPasswordAndMasterKeyHash())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -203,17 +203,45 @@ export class ContextMenuClickedHandler {
|
||||
if (tab == null) {
|
||||
return;
|
||||
}
|
||||
await this.autofillAction(tab, cipher);
|
||||
|
||||
if (cipher.reprompt !== CipherRepromptType.None) {
|
||||
await BrowserApi.tabSendMessageData(tab, "passwordReprompt", {
|
||||
cipherId: cipher.id,
|
||||
action: AUTOFILL_ID,
|
||||
});
|
||||
} else {
|
||||
await this.autofillAction(tab, cipher);
|
||||
}
|
||||
|
||||
break;
|
||||
case COPY_USERNAME_ID:
|
||||
this.copyToClipboard({ text: cipher.login.username, tab: tab });
|
||||
break;
|
||||
case COPY_PASSWORD_ID:
|
||||
this.copyToClipboard({ text: cipher.login.password, tab: tab });
|
||||
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedPassword, cipher.id);
|
||||
if (cipher.reprompt !== CipherRepromptType.None) {
|
||||
await BrowserApi.tabSendMessageData(tab, "passwordReprompt", {
|
||||
cipherId: cipher.id,
|
||||
action: COPY_PASSWORD_ID,
|
||||
});
|
||||
} else {
|
||||
this.copyToClipboard({ text: cipher.login.password, tab: tab });
|
||||
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedPassword, cipher.id);
|
||||
}
|
||||
|
||||
break;
|
||||
case COPY_VERIFICATIONCODE_ID:
|
||||
this.copyToClipboard({ text: await this.totpService.getCode(cipher.login.totp), tab: tab });
|
||||
if (cipher.reprompt !== CipherRepromptType.None) {
|
||||
await BrowserApi.tabSendMessageData(tab, "passwordReprompt", {
|
||||
cipherId: cipher.id,
|
||||
action: COPY_VERIFICATIONCODE_ID,
|
||||
});
|
||||
} else {
|
||||
this.copyToClipboard({
|
||||
text: await this.totpService.getCode(cipher.login.totp),
|
||||
tab: tab,
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ window.addEventListener(
|
||||
|
||||
const forwardCommands = [
|
||||
"promptForLogin",
|
||||
"passwordReprompt",
|
||||
"addToLockedVaultPendingNotifications",
|
||||
"unlockCompleted",
|
||||
"addedCipher",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
||||
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { EventType, FieldType, UriMatchType } from "@bitwarden/common/enums";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@ -45,7 +46,8 @@ export default class AutofillService implements AutofillServiceInterface {
|
||||
private totpService: TotpService,
|
||||
private eventCollectionService: EventCollectionService,
|
||||
private logService: LogService,
|
||||
private settingsService: SettingsService
|
||||
private settingsService: SettingsService,
|
||||
private userVerificationService: UserVerificationService
|
||||
) {}
|
||||
|
||||
getFormsWithPasswordFields(pageDetails: AutofillPageDetails): FormData[] {
|
||||
@ -234,7 +236,19 @@ export default class AutofillService implements AutofillServiceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
if (cipher == null || cipher.reprompt !== CipherRepromptType.None) {
|
||||
if (cipher == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
cipher.reprompt !== CipherRepromptType.None &&
|
||||
(await this.userVerificationService.hasMasterPasswordAndMasterKeyHash())
|
||||
) {
|
||||
await BrowserApi.tabSendMessageData(tab, "passwordReprompt", {
|
||||
cipherId: cipher.id,
|
||||
action: "autofill",
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||
|
||||
import { BrowserStateService } from "../platform/services/abstractions/browser-state.service";
|
||||
|
@ -1,27 +1,33 @@
|
||||
import { AvatarUpdateService as AvatarUpdateServiceAbstraction } from "@bitwarden/common/abstractions/account/avatar-update.service";
|
||||
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { DevicesServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices.service.abstraction";
|
||||
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
|
||||
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
|
||||
import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service";
|
||||
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
|
||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
||||
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service";
|
||||
import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction";
|
||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction";
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthRequestCryptoServiceImplementation } from "@bitwarden/common/auth/services/auth-request-crypto.service.implementation";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device-trust-crypto.service.implementation";
|
||||
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service";
|
||||
@ -60,12 +66,13 @@ import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/we
|
||||
import { AvatarUpdateService } from "@bitwarden/common/services/account/avatar-update.service";
|
||||
import { ApiService } from "@bitwarden/common/services/api.service";
|
||||
import { AuditService } from "@bitwarden/common/services/audit.service";
|
||||
import { DevicesServiceImplementation } from "@bitwarden/common/services/devices/devices.service.implementation";
|
||||
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
|
||||
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
|
||||
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
|
||||
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||
import { TotpService } from "@bitwarden/common/services/totp.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
|
||||
import {
|
||||
PasswordGenerationService,
|
||||
PasswordGenerationServiceAbstraction,
|
||||
@ -136,7 +143,7 @@ import { PopupUtilsService } from "../popup/services/popup-utils.service";
|
||||
import { BrowserSendService } from "../services/browser-send.service";
|
||||
import { BrowserSettingsService } from "../services/browser-settings.service";
|
||||
import { BrowserFido2UserInterfaceService } from "../services/fido2/browser-fido2-user-interface.service";
|
||||
import VaultTimeoutService from "../services/vaultTimeout/vaultTimeout.service";
|
||||
import VaultTimeoutService from "../services/vault-timeout/vault-timeout.service";
|
||||
import { BrowserFolderService } from "../vault/services/browser-folder.service";
|
||||
import { VaultFilterService } from "../vault/services/vault-filter.service";
|
||||
|
||||
@ -164,7 +171,7 @@ export default class MainBackground {
|
||||
cipherService: CipherServiceAbstraction;
|
||||
folderService: InternalFolderServiceAbstraction;
|
||||
collectionService: CollectionServiceAbstraction;
|
||||
vaultTimeoutService: VaultTimeoutServiceAbstraction;
|
||||
vaultTimeoutService: VaultTimeoutService;
|
||||
vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction;
|
||||
syncService: SyncServiceAbstraction;
|
||||
passwordGenerationService: PasswordGenerationServiceAbstraction;
|
||||
@ -207,6 +214,10 @@ export default class MainBackground {
|
||||
cipherContextMenuHandler: CipherContextMenuHandler;
|
||||
configService: ConfigServiceAbstraction;
|
||||
configApiService: ConfigApiServiceAbstraction;
|
||||
devicesApiService: DevicesApiServiceAbstraction;
|
||||
devicesService: DevicesServiceAbstraction;
|
||||
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction;
|
||||
authRequestCryptoService: AuthRequestCryptoServiceAbstraction;
|
||||
popupUtilsService: PopupUtilsService;
|
||||
browserPopoutWindowService: BrowserPopoutWindowService;
|
||||
|
||||
@ -399,6 +410,23 @@ export default class MainBackground {
|
||||
that.runtimeBackground.processMessage(message, that as any);
|
||||
};
|
||||
})();
|
||||
|
||||
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
|
||||
this.deviceTrustCryptoService = new DeviceTrustCryptoService(
|
||||
this.cryptoFunctionService,
|
||||
this.cryptoService,
|
||||
this.encryptService,
|
||||
this.stateService,
|
||||
this.appIdService,
|
||||
this.devicesApiService,
|
||||
this.i18nService,
|
||||
this.platformUtilsService
|
||||
);
|
||||
|
||||
this.devicesService = new DevicesServiceImplementation(this.devicesApiService);
|
||||
|
||||
this.authRequestCryptoService = new AuthRequestCryptoServiceImplementation(this.cryptoService);
|
||||
|
||||
this.authService = new AuthService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
@ -414,14 +442,26 @@ export default class MainBackground {
|
||||
this.i18nService,
|
||||
this.encryptService,
|
||||
this.passwordStrengthService,
|
||||
this.policyService
|
||||
this.policyService,
|
||||
this.deviceTrustCryptoService,
|
||||
this.authRequestCryptoService
|
||||
);
|
||||
|
||||
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
||||
|
||||
this.userVerificationService = new UserVerificationService(
|
||||
this.stateService,
|
||||
this.cryptoService,
|
||||
this.i18nService,
|
||||
this.userVerificationApiService
|
||||
);
|
||||
|
||||
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
||||
this.cryptoService,
|
||||
this.tokenService,
|
||||
this.policyService,
|
||||
this.stateService
|
||||
this.stateService,
|
||||
this.userVerificationService
|
||||
);
|
||||
|
||||
this.vaultTimeoutService = new VaultTimeoutService(
|
||||
@ -432,7 +472,6 @@ export default class MainBackground {
|
||||
this.platformUtilsService,
|
||||
this.messagingService,
|
||||
this.searchService,
|
||||
this.keyConnectorService,
|
||||
this.stateService,
|
||||
this.authService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
@ -483,13 +522,15 @@ export default class MainBackground {
|
||||
this.eventUploadService
|
||||
);
|
||||
this.totpService = new TotpService(this.cryptoFunctionService, this.logService);
|
||||
|
||||
this.autofillService = new AutofillService(
|
||||
this.cipherService,
|
||||
this.stateService,
|
||||
this.totpService,
|
||||
this.eventCollectionService,
|
||||
this.logService,
|
||||
this.settingsService
|
||||
this.settingsService,
|
||||
this.userVerificationService
|
||||
);
|
||||
this.auditService = new AuditService(this.cryptoFunctionService, this.apiService);
|
||||
this.exportService = new VaultExportService(
|
||||
@ -511,15 +552,6 @@ export default class MainBackground {
|
||||
this.authService,
|
||||
this.messagingService
|
||||
);
|
||||
|
||||
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
||||
|
||||
this.userVerificationService = new UserVerificationService(
|
||||
this.cryptoService,
|
||||
this.i18nService,
|
||||
this.userVerificationApiService
|
||||
);
|
||||
|
||||
this.configApiService = new ConfigApiService(this.apiService, this.authService);
|
||||
|
||||
this.configService = new ConfigService(
|
||||
@ -528,6 +560,7 @@ export default class MainBackground {
|
||||
this.authService,
|
||||
this.environmentService
|
||||
);
|
||||
|
||||
this.browserPopoutWindowService = new BrowserPopoutWindowService();
|
||||
|
||||
this.popupUtilsService = new PopupUtilsService(this.isPrivateMode);
|
||||
@ -669,7 +702,8 @@ export default class MainBackground {
|
||||
this.cipherContextMenuHandler = new CipherContextMenuHandler(
|
||||
this.mainContextMenuHandler,
|
||||
this.authService,
|
||||
this.cipherService
|
||||
this.cipherService,
|
||||
this.userVerificationService
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -679,7 +713,7 @@ export default class MainBackground {
|
||||
|
||||
await this.stateService.init();
|
||||
|
||||
await (this.vaultTimeoutService as VaultTimeoutService).init(true);
|
||||
await this.vaultTimeoutService.init(true);
|
||||
await (this.i18nService as BrowserI18nService).init();
|
||||
await (this.eventUploadService as EventUploadService).init(true);
|
||||
await this.runtimeBackground.init();
|
||||
|
@ -10,7 +10,11 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import {
|
||||
MasterKey,
|
||||
SymmetricCryptoKey,
|
||||
UserKey,
|
||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
|
||||
import { BrowserApi } from "../platform/browser/browser-api";
|
||||
|
||||
@ -42,6 +46,7 @@ type ReceiveMessage = {
|
||||
|
||||
// Unlock key
|
||||
keyB64?: string;
|
||||
userKeyB64?: string;
|
||||
};
|
||||
|
||||
type ReceiveMessageOuter = {
|
||||
@ -320,16 +325,55 @@ export class NativeMessagingBackground {
|
||||
}
|
||||
|
||||
if (message.response === "unlocked") {
|
||||
await this.cryptoService.setKey(
|
||||
new SymmetricCryptoKey(Utils.fromB64ToArray(message.keyB64))
|
||||
);
|
||||
try {
|
||||
if (message.userKeyB64) {
|
||||
const userKey = new SymmetricCryptoKey(
|
||||
Utils.fromB64ToArray(message.userKeyB64)
|
||||
) as UserKey;
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
} else if (message.keyB64) {
|
||||
// Backwards compatibility to support cases in which the user hasn't updated their desktop app
|
||||
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3472)
|
||||
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||
encUserKey ||= await this.stateService.getMasterKeyEncryptedUserKey();
|
||||
if (!encUserKey) {
|
||||
throw new Error("No encrypted user key found");
|
||||
}
|
||||
const masterKey = new SymmetricCryptoKey(
|
||||
Utils.fromB64ToArray(message.keyB64)
|
||||
) as MasterKey;
|
||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
|
||||
masterKey,
|
||||
new EncString(encUserKey)
|
||||
);
|
||||
await this.cryptoService.setMasterKey(masterKey);
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
} else {
|
||||
throw new Error("No key received");
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error("Unable to set key: " + e);
|
||||
this.messagingService.send("showDialog", {
|
||||
title: { key: "biometricsFailedTitle" },
|
||||
content: { key: "biometricsFailedDesc" },
|
||||
acceptButtonText: { key: "ok" },
|
||||
cancelButtonText: null,
|
||||
type: "danger",
|
||||
});
|
||||
|
||||
// Exit early
|
||||
if (this.resolver) {
|
||||
this.resolver(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify key is correct by attempting to decrypt a secret
|
||||
try {
|
||||
await this.cryptoService.getFingerprint(await this.stateService.getUserId());
|
||||
} catch (e) {
|
||||
this.logService.error("Unable to verify key: " + e);
|
||||
await this.cryptoService.clearKey();
|
||||
await this.cryptoService.clearKeys();
|
||||
this.showWrongUserDialog();
|
||||
|
||||
// Exit early
|
||||
|
@ -52,7 +52,11 @@ export default class RuntimeBackground {
|
||||
sender: chrome.runtime.MessageSender,
|
||||
sendResponse: any
|
||||
) => {
|
||||
const messagesWithResponse = ["fido2RegisterCredentialRequest", "fido2GetCredentialRequest"];
|
||||
const messagesWithResponse = [
|
||||
"checkFido2FeatureEnabled",
|
||||
"fido2RegisterCredentialRequest",
|
||||
"fido2GetCredentialRequest",
|
||||
];
|
||||
|
||||
if (messagesWithResponse.includes(msg.command)) {
|
||||
this.processMessage(msg, sender).then(
|
||||
@ -75,6 +79,8 @@ export default class RuntimeBackground {
|
||||
}
|
||||
|
||||
async processMessage(msg: any, sender: chrome.runtime.MessageSender) {
|
||||
const cipherId = msg.data?.cipherId;
|
||||
|
||||
switch (msg.command) {
|
||||
case "loggedIn":
|
||||
case "unlocked": {
|
||||
@ -82,7 +88,7 @@ export default class RuntimeBackground {
|
||||
|
||||
if (this.lockedVaultPendingNotifications?.length > 0) {
|
||||
item = this.lockedVaultPendingNotifications.pop();
|
||||
await this.browserPopoutWindowService.closeLoginPrompt();
|
||||
await this.browserPopoutWindowService.closeUnlockPrompt();
|
||||
}
|
||||
|
||||
await this.main.refreshBadge();
|
||||
@ -122,13 +128,22 @@ export default class RuntimeBackground {
|
||||
break;
|
||||
case "promptForLogin":
|
||||
case "bgReopenPromptForLogin":
|
||||
await this.browserPopoutWindowService.openLoginPrompt(sender.tab?.windowId);
|
||||
await this.browserPopoutWindowService.openUnlockPrompt(sender.tab?.windowId);
|
||||
break;
|
||||
case "passwordReprompt":
|
||||
if (cipherId) {
|
||||
await this.browserPopoutWindowService.openPasswordRepromptPrompt(sender.tab?.windowId, {
|
||||
cipherId: cipherId,
|
||||
senderTabId: sender.tab.id,
|
||||
action: msg.data?.action,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "openAddEditCipher": {
|
||||
const addEditCipherUrl =
|
||||
msg.data?.cipherId == null
|
||||
cipherId == null
|
||||
? "popup/index.html#/edit-cipher"
|
||||
: "popup/index.html#/edit-cipher?cipherId=" + msg.data.cipherId;
|
||||
: "popup/index.html#/edit-cipher?cipherId=" + cipherId;
|
||||
|
||||
BrowserApi.openBitwardenExtensionTab(addEditCipherUrl, true);
|
||||
break;
|
||||
@ -233,6 +248,8 @@ export default class RuntimeBackground {
|
||||
case "fido2AbortRequest":
|
||||
this.abortControllers.get(msg.abortedRequestId)?.abort();
|
||||
break;
|
||||
case "checkFido2FeatureEnabled":
|
||||
return await this.main.fido2ClientService.isFido2FeatureEnabled();
|
||||
case "fido2RegisterCredentialRequest":
|
||||
return await this.main.fido2ClientService
|
||||
.createCredential(msg.data, this.createAbortController(msg.requestId))
|
||||
|
@ -0,0 +1,28 @@
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||
|
||||
import {
|
||||
ApiServiceInitOptions,
|
||||
apiServiceFactory,
|
||||
} from "../../platform/background/service-factories/api-service.factory";
|
||||
import {
|
||||
FactoryOptions,
|
||||
CachedServices,
|
||||
factory,
|
||||
} from "../../platform/background/service-factories/factory-options";
|
||||
|
||||
type DevicesApiServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type DevicesApiServiceInitOptions = DevicesApiServiceFactoryOptions & ApiServiceInitOptions;
|
||||
|
||||
export function devicesApiServiceFactory(
|
||||
cache: { devicesApiService?: DevicesApiServiceAbstraction } & CachedServices,
|
||||
opts: DevicesApiServiceInitOptions
|
||||
): Promise<DevicesApiServiceAbstraction> {
|
||||
return factory(
|
||||
cache,
|
||||
"devicesApiService",
|
||||
opts,
|
||||
async () => new DevicesApiServiceImplementation(await apiServiceFactory(cache, opts))
|
||||
);
|
||||
}
|
@ -1,13 +1,9 @@
|
||||
import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
|
||||
import {
|
||||
authServiceFactory,
|
||||
AuthServiceInitOptions,
|
||||
} from "../../auth/background/service-factories/auth-service.factory";
|
||||
import {
|
||||
keyConnectorServiceFactory,
|
||||
KeyConnectorServiceInitOptions,
|
||||
} from "../../auth/background/service-factories/key-connector-service.factory";
|
||||
import {
|
||||
CryptoServiceInitOptions,
|
||||
cryptoServiceFactory,
|
||||
@ -29,7 +25,7 @@ import {
|
||||
StateServiceInitOptions,
|
||||
stateServiceFactory,
|
||||
} from "../../platform/background/service-factories/state-service.factory";
|
||||
import VaultTimeoutService from "../../services/vaultTimeout/vaultTimeout.service";
|
||||
import VaultTimeoutService from "../../services/vault-timeout/vault-timeout.service";
|
||||
import {
|
||||
cipherServiceFactory,
|
||||
CipherServiceInitOptions,
|
||||
@ -64,7 +60,6 @@ export type VaultTimeoutServiceInitOptions = VaultTimeoutServiceFactoryOptions &
|
||||
PlatformUtilsServiceInitOptions &
|
||||
MessagingServiceInitOptions &
|
||||
SearchServiceInitOptions &
|
||||
KeyConnectorServiceInitOptions &
|
||||
StateServiceInitOptions &
|
||||
AuthServiceInitOptions &
|
||||
VaultTimeoutSettingsServiceInitOptions;
|
||||
@ -86,7 +81,6 @@ export function vaultTimeoutServiceFactory(
|
||||
await platformUtilsServiceFactory(cache, opts),
|
||||
await messagingServiceFactory(cache, opts),
|
||||
await searchServiceFactory(cache, opts),
|
||||
await keyConnectorServiceFactory(cache, opts),
|
||||
await stateServiceFactory(cache, opts),
|
||||
await authServiceFactory(cache, opts),
|
||||
await vaultTimeoutSettingsServiceFactory(cache, opts),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user