1
0
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:
gbubemismith 2023-08-24 14:42:09 -04:00
commit 91324876c6
No known key found for this signature in database
644 changed files with 16796 additions and 7903 deletions

View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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",

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "استعادة العنصر"
},
"restoreItemConfirmation": {
"message": "هل أنت متأكد من أنك تريد استعادة هذا العنصر؟"
},
"restoredItem": {
"message": "تم استعادة العنصر"
},

View File

@ -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"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Аднавіць элемент"
},
"restoreItemConfirmation": {
"message": "Вы сапраўды хочаце аднавіць гэты элемент?"
},
"restoredItem": {
"message": "Элемент адноўлены"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Възстановяване на запис"
},
"restoreItemConfirmation": {
"message": "Сигурни ли сте, че искате да възстановите записа?"
},
"restoredItem": {
"message": "Записът е възстановен"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "বস্তু পুনরুদ্ধার"
},
"restoreItemConfirmation": {
"message": "আপনি কি নিশ্চিত যে আপনি এই বস্তুটি পুনরুদ্ধার করতে চান?"
},
"restoredItem": {
"message": "বস্তু পুনরুদ্ধারকৃত"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restaura l'element"
},
"restoreItemConfirmation": {
"message": "Esteu segur que voleu restaurar aquest element?"
},
"restoredItem": {
"message": "Element restaurat"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Obnovit položku"
},
"restoreItemConfirmation": {
"message": "Opravdu chcete tuto položku obnovit?"
},
"restoredItem": {
"message": "Položka byla obnovena"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Adfer yr eitem"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Gendan element"
},
"restoreItemConfirmation": {
"message": "Er du sikker på, at du vil gendanne dette element?"
},
"restoredItem": {
"message": "Element gendannet"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Eintrag wiederherstellen"
},
"restoreItemConfirmation": {
"message": "Soll dieser Eintrag wirklich wiederhergestellt werden?"
},
"restoredItem": {
"message": "Eintrag wiederhergestellt"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Ανάκτηση Στοιχείου"
},
"restoreItemConfirmation": {
"message": "Είστε βέβαιοι ότι θέλετε να ανακτήσετε αυτό το στοιχείο;"
},
"restoredItem": {
"message": "Στοιχείο που έχει Ανακτηθεί"
},

View File

@ -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"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Restored item"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restaurar elemento"
},
"restoreItemConfirmation": {
"message": "¿Estás seguro de que quieres restaurar este elemento?"
},
"restoredItem": {
"message": "Elemento restaurado"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Taasta kirje"
},
"restoreItemConfirmation": {
"message": "Oled kindel, et soovid selle kirje taastada?"
},
"restoredItem": {
"message": "Kirje on taastatud"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Berreskuratu elementua"
},
"restoreItemConfirmation": {
"message": "Ziur zaude elementu hau berreskuratu nahi duzula?"
},
"restoredItem": {
"message": "Elementua berreskuratua"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "بازیابی مورد"
},
"restoreItemConfirmation": {
"message": "آیا مطمئن هستید که می‌خواهید این مورد را بازیابی کنید؟"
},
"restoredItem": {
"message": "مورد بازیابی شد"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Palauta kohde"
},
"restoreItemConfirmation": {
"message": "Haluatko varmasti palauttaa kohteen?"
},
"restoredItem": {
"message": "Kohde palautettiin"
},

View File

@ -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"
},

View File

@ -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é"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "שחזר פריט"
},
"restoreItemConfirmation": {
"message": "האם אתה בטוח שברצונך לשחזר פריט זה?"
},
"restoredItem": {
"message": "פריט ששוחזר"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "आइटम बहाल करें"
},
"restoreItemConfirmation": {
"message": "क्या आप सुनिश्चित हैं कि आप इस आइटम को बहाल करना चाहते हैं?"
},
"restoredItem": {
"message": "बहाल आइटम"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Vrati stavku"
},
"restoreItemConfirmation": {
"message": "Sigurno želiš vratiti ovu stavku?"
},
"restoredItem": {
"message": "Stavka vraćena"
},

View File

@ -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"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Pulihkan Item"
},
"restoreItemConfirmation": {
"message": "Apakah Anda yakin ingin memulihkan item ini?"
},
"restoredItem": {
"message": "Item Yang Dipulihkan"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Ripristina elemento"
},
"restoreItemConfirmation": {
"message": "Sei sicuro di voler ripristinare questo elemento?"
},
"restoredItem": {
"message": "Elemento ripristinato"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "アイテムをリストア"
},
"restoreItemConfirmation": {
"message": "このアイテムをリストアしますか?"
},
"restoredItem": {
"message": "リストアされたアイテム"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "ಐಟಂ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ"
},
"restoreItemConfirmation": {
"message": "ಈ ಐಟಂ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?"
},
"restoredItem": {
"message": "ಐಟಂ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲಾಗಿದೆ"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "항목 복원"
},
"restoreItemConfirmation": {
"message": "정말 이 항목을 복원하시겠습니까?"
},
"restoredItem": {
"message": "복원된 항목"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Atkurti elementą"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Elementas atkurtas"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Atjaunot vienumu"
},
"restoreItemConfirmation": {
"message": "Jūs tiešām atjaunot šo vienumu?"
},
"restoredItem": {
"message": "Vienums atjaunots"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "ഇനം വീണ്ടെടുക്കുക "
},
"restoreItemConfirmation": {
"message": "ഈ ഇനം വീണ്ടെടുക്കണമെന്ന് ഉറപ്പാണോ?"
},
"restoredItem": {
"message": "വീണ്ടെടുത്ത ഇനം"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Gjenopprett objekt"
},
"restoreItemConfirmation": {
"message": "Er du sikker på at du vil gjenopprette dette elementet?"
},
"restoredItem": {
"message": "Gjenopprettet objekt"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Item herstellen"
},
"restoreItemConfirmation": {
"message": "Weet je zeker dat je dit item wilt herstellen?"
},
"restoredItem": {
"message": "Hersteld item"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Przywróć element"
},
"restoreItemConfirmation": {
"message": "Czy na pewno chcesz przywrócić ten element?"
},
"restoredItem": {
"message": "Element został przywrócony"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restaurar Item"
},
"restoreItemConfirmation": {
"message": "Você tem certeza que deseja restaurar esse item?"
},
"restoredItem": {
"message": "Item Restaurado"
},

View File

@ -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"

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restabilire articol"
},
"restoreItemConfirmation": {
"message": "Sigur doriți să restabiliți acest articol?"
},
"restoredItem": {
"message": "Articol restabilit"
},

View File

@ -631,7 +631,7 @@
"message": "Обновить"
},
"notificationUnlockDesc": {
"message": "Разблокируйте свое хранилище Bitwarden для завершения запроса автозаполнения."
"message": "Разблокируйте свое хранилище Bitwarden чтобы выполнить автозаполнение."
},
"notificationUnlock": {
"message": "Разблокировать"
@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Восстановить элемент"
},
"restoreItemConfirmation": {
"message": "Вы уверены, что хотите восстановить этот элемент?"
},
"restoredItem": {
"message": "Элемент восстановлен"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "අයිතමය යළි පිහිටුවන්න"
},
"restoreItemConfirmation": {
"message": "ඔබට මෙම අයිතමය යථා තත්වයට පත් කිරීමට අවශ්ය බව ඔබට විශ්වාසද?"
},
"restoredItem": {
"message": "ප්රතිෂ්ඨාපනය අයිතමය"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Obnoviť položku"
},
"restoreItemConfirmation": {
"message": "Naozaj chcete obnoviť túto položku?"
},
"restoredItem": {
"message": "Obnovená položka"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Obnovi element"
},
"restoreItemConfirmation": {
"message": "Ste prepričani, da želite obnoviti ta element?"
},
"restoredItem": {
"message": "Element obnovljen"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Врати ставку"
},
"restoreItemConfirmation": {
"message": "Да ли сте сигурни да желите да вратите ову ставку?"
},
"restoredItem": {
"message": "Ставка враћена"
},

View File

@ -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"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "Restore item"
},
"restoreItemConfirmation": {
"message": "Are you sure you want to restore this item?"
},
"restoredItem": {
"message": "Item restored"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "กู้คืนรายการ"
},
"restoreItemConfirmation": {
"message": "คุณแน่ใจหรือไม่ว่าต้องการกู้คืนรายการนี้"
},
"restoredItem": {
"message": "คืนค่ารายการแล้ว"
},

View File

@ -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"
},

View File

@ -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": "Відкривається у новому вікні"

View File

@ -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"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "恢复项目"
},
"restoreItemConfirmation": {
"message": "您确定要恢复此项目吗?"
},
"restoredItem": {
"message": "项目已恢复"
},

View File

@ -1446,9 +1446,6 @@
"restoreItem": {
"message": "還原項目"
},
"restoreItemConfirmation": {
"message": "您確定要還原此項目嗎?"
},
"restoredItem": {
"message": "項目已還原"
},

View File

@ -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))
);
}

View File

@ -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)
)
);
}

View File

@ -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)
)
);
}

View File

@ -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))
);
}

View File

@ -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)
)
);
}

View File

@ -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"

View File

@ -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;
}

View File

@ -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>

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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";

View File

@ -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,

View File

@ -1,2 +1 @@
export { LockGuardService } from "./lock-guard.service";
export { UnauthGuardService } from "./unauth-guard.service";

View File

@ -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";
}

View File

@ -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 {

View File

@ -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,

View File

@ -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();
};
}
}

View File

@ -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;
};
}
});

View File

@ -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)
)
);
}

View File

@ -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
);
});
});
});

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -28,6 +28,7 @@ window.addEventListener(
const forwardCommands = [
"promptForLogin",
"passwordReprompt",
"addToLockedVaultPendingNotifications",
"unlockCompleted",
"addedCipher",

View File

@ -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;
}

View File

@ -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";

View File

@ -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";

View File

@ -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();

View File

@ -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

View File

@ -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))

View File

@ -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))
);
}

View File

@ -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