Conflict resolution

This commit is contained in:
Carlos Gonçalves 2024-04-02 17:18:45 +01:00
parent 8a1df6671a
commit 0c0c2039ed
No known key found for this signature in database
GPG Key ID: 8147F618E732EF25
699 changed files with 17230 additions and 8095 deletions

View File

@ -7,5 +7,6 @@ checkmarx:
scan:
configs:
sast:
presetName: "BW ASA Premium"
# Exclude spec files, and test specific files
filter: "!*.spec.ts,!**/spec/**,!apps/desktop/native-messaging-test-runner/**"

View File

@ -67,7 +67,7 @@
"pathGroupsExcludedImportTypes": ["builtin"]
}
],
"rxjs-angular/prefer-takeuntil": "error",
"rxjs-angular/prefer-takeuntil": ["error", { "alias": ["takeUntilDestroyed"] }],
"rxjs/no-exposed-subjects": ["error", { "allowProtected": true }],
"no-restricted-syntax": [
"error",
@ -191,6 +191,15 @@
]
}
},
{
"files": ["libs/tools/export/vault-export/vault-export-ui/src/**/*.ts"],
"rules": {
"no-restricted-imports": [
"error",
{ "patterns": ["@bitwarden/vault-export-ui/*", "src/**/*"] }
]
}
},
{
"files": ["libs/importer/src/**/*.ts"],
"rules": {

1
.github/CODEOWNERS vendored
View File

@ -83,6 +83,7 @@ apps/web/src/translation-constants.ts @bitwarden/team-platform-dev
## Autofill team files ##
apps/browser/src/autofill @bitwarden/team-autofill-dev
apps/desktop/src/autofill @bitwarden/team-autofill-dev
libs/common/src/autofill @bitwarden/team-autofill-dev
## Component Library ##

View File

@ -16,6 +16,10 @@
"matchManagers": ["cargo"],
"commitMessagePrefix": "[deps] Platform:"
},
{
"groupName": "napi",
"matchPackageNames": ["napi", "napi-build", "napi-derive"]
},
{
"matchPackageNames": ["typescript", "zone.js"],
"matchUpdateTypes": ["major", "minor"],

View File

@ -444,7 +444,10 @@ jobs:
macos-build:
name: MacOS Build
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs: setup
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
@ -602,7 +605,10 @@ jobs:
macos-package-github:
name: MacOS Package GitHub Release Assets
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs:
- browser-build
- macos-build
@ -808,7 +814,10 @@ jobs:
macos-package-mas:
name: MacOS Package Prod Release Asset
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs:
- browser-build
- macos-build
@ -1006,7 +1015,10 @@ jobs:
macos-package-dev:
name: MacOS Package Dev Release Asset
if: false # We need to look into how code signing works for dev
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs:
- browser-build
- macos-build

View File

@ -299,7 +299,7 @@ jobs:
keyvault: "bitwarden-ci"
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
- name: Trigger web vault deploy
- name: Trigger web vault deploy using GitHub Run ID
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
@ -311,7 +311,7 @@ jobs:
ref: 'main',
inputs: {
'environment': 'USDEV',
'branch-or-tag': 'main'
'build-web-run-id': '${{ github.run_id }}'
}
})

View File

@ -27,6 +27,10 @@ on:
description: "Debug mode"
type: boolean
default: true
build-web-run-id:
description: "Build-web workflow Run ID to use for artifact download"
type: string
required: false
workflow_call:
inputs:
@ -46,6 +50,10 @@ on:
description: "Debug mode"
type: boolean
default: true
build-web-run-id:
description: "Build-web workflow Run ID to use for artifact download"
type: string
required: false
permissions:
deployments: write
@ -168,7 +176,20 @@ jobs:
env:
_ENVIRONMENT_ARTIFACT: ${{ needs.setup.outputs.environment-artifact }}
steps:
- name: 'Download latest cloud asset using GitHub Run ID: ${{ inputs.build-web-run-id }}'
if: ${{ inputs.build-web-run-id }}
uses: bitwarden/gh-actions/download-artifacts@main
id: download-latest-artifacts
continue-on-error: true
with:
workflow: build-web.yml
path: apps/web
workflow_conclusion: success
run_id: ${{ inputs.build-web-run-id }}
artifacts: ${{ env._ENVIRONMENT_ARTIFACT }}
- name: 'Download latest cloud asset from branch/tag: ${{ inputs.branch-or-tag }}'
if: ${{ !inputs.build-web-run-id }}
uses: bitwarden/gh-actions/download-artifacts@main
id: download-artifacts
continue-on-error: true
@ -249,7 +270,20 @@ jobs:
keyvault: ${{ needs.setup.outputs.retrieve-secrets-keyvault }}
secrets: "sa-bitwarden-web-vault-name,sp-bitwarden-web-vault-password,sp-bitwarden-web-vault-appid,sp-bitwarden-web-vault-tenant"
- name: 'Download latest cloud asset using GitHub Run ID: ${{ inputs.build-web-run-id }}'
if: ${{ inputs.build-web-run-id }}
uses: bitwarden/gh-actions/download-artifacts@main
id: download-latest-artifacts
continue-on-error: true
with:
workflow: build-web.yml
path: apps/web
workflow_conclusion: success
run_id: ${{ inputs.build-web-run-id }}
artifacts: ${{ env._ENVIRONMENT_ARTIFACT }}
- name: 'Download cloud asset from branch/tag: ${{ inputs.branch-or-tag }}'
if: ${{ !inputs.build-web-run-id }}
uses: bitwarden/gh-actions/download-artifacts@main
with:
workflow: build-web.yml

View File

@ -393,7 +393,10 @@ jobs:
macos-build:
name: MacOS Build
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs: setup
env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
@ -522,7 +525,10 @@ jobs:
macos-package-github:
name: MacOS Package GitHub Release Assets
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs:
- setup
- macos-build
@ -732,7 +738,10 @@ jobs:
macos-package-mas:
name: MacOS Package Prod Release Asset
runs-on: macos-13
# Note, this workflow is running on macOS 11 to maintain compatibility with macOS 10.15 Catalina,
# as the newer versions will case the native modules to be incompatible with older macOS systems
# This version should stay pinned until we drop support for macOS 10.15, or we drop the native modules
runs-on: macos-11
needs:
- setup
- macos-build

View File

@ -113,105 +113,12 @@ jobs:
- name: Log out of Docker
run: docker logout
ghpages-deploy:
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 }}
_BRANCH: "v${{ needs.setup.outputs.release_version }}-deploy"
steps:
- name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve bot secrets
id: retrieve-bot-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: bitwarden-ci
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
- name: Checkout GH pages repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
repository: bitwarden/web-vault-pages
path: ghpages-deployment
token: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
- name: Download latest cloud asset
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@main
with:
workflow: build-web.yml
path: assets
workflow_conclusion: success
branch: ${{ github.ref_name }}
artifacts: web-*-cloud-COMMERCIAL.zip
- name: Dry Run - Download latest cloud asset
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@main
with:
workflow: build-web.yml
path: assets
workflow_conclusion: success
branch: main
artifacts: web-*-cloud-COMMERCIAL.zip
- name: Unzip build asset
working-directory: assets
run: unzip web-*-cloud-COMMERCIAL.zip
- name: Create new branch
run: |
cd ${{ github.workspace }}/ghpages-deployment
git config user.name = "GitHub Action Bot"
git config user.email = "<>"
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: |
git add .
git commit -m "Deploy Web v${_RELEASE_VERSION} to GitHub Pages"
git push --set-upstream origin ${_BRANCH} --force
- name: Create GitHub Pages Deploy PR
working-directory: ghpages-deployment
env:
GITHUB_TOKEN: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
run: |
if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then
gh pr create --title "Deploy v${_RELEASE_VERSION} to GitHub Pages" \
--draft \
--body "Deploying v${_RELEASE_VERSION}" \
--base main \
--head "${_BRANCH}"
else
gh pr create --title "Deploy v${_RELEASE_VERSION} to GitHub Pages" \
--body "Deploying v${_RELEASE_VERSION}" \
--base main \
--head "${_BRANCH}"
fi
release:
name: Create GitHub Release
runs-on: ubuntu-22.04
needs:
- setup
- self-host
- ghpages-deploy
steps:
- name: Create GitHub deployment
if: ${{ github.event.inputs.release_type != 'Dry Run' }}

View File

@ -10,8 +10,6 @@ on:
pull_request_target:
types: [opened, synchronize]
permissions: read-all
jobs:
check-run:
name: Check PR run
@ -22,6 +20,8 @@ jobs:
runs-on: ubuntu-22.04
needs: check-run
permissions:
contents: read
pull-requests: write
security-events: write
steps:
@ -43,7 +43,7 @@ jobs:
additional_params: --report-format sarif --output-path . ${{ env.INCREMENTAL }}
- name: Upload Checkmarx results to GitHub
uses: github/codeql-action/upload-sarif@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
with:
sarif_file: cx_result.sarif
@ -51,6 +51,9 @@ jobs:
name: Quality scan
runs-on: ubuntu-22.04
needs: check-run
permissions:
contents: read
pull-requests: write
steps:
- name: Check out repo

View File

@ -367,21 +367,27 @@ jobs:
id: set-final-version-output
run: |
if [[ "${{ steps.bump-browser-version-override.outcome }}" = "success" ]]; then
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
echo "version_browser=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-browser-version-automatic.outcome }}" = "success" ]]; then
echo "version=${{ steps.calculate-next-browser-version.outputs.version }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-cli-version-override.outcome }}" = "success" ]]; then
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
echo "version_browser=${{ steps.calculate-next-browser-version.outputs.version }}" >> $GITHUB_OUTPUT
fi
if [[ "${{ steps.bump-cli-version-override.outcome }}" = "success" ]]; then
echo "version_cli=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-cli-version-automatic.outcome }}" = "success" ]]; then
echo "version=${{ steps.calculate-next-cli-version.outputs.version }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-desktop-version-override.outcome }}" = "success" ]]; then
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
echo "version_cli=${{ steps.calculate-next-cli-version.outputs.version }}" >> $GITHUB_OUTPUT
fi
if [[ "${{ steps.bump-desktop-version-override.outcome }}" = "success" ]]; then
echo "version_desktop=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-desktop-version-automatic.outcome }}" = "success" ]]; then
echo "version=${{ steps.calculate-next-desktop-version.outputs.version }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-web-version-override.outcome }}" = "success" ]]; then
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
echo "version_desktop=${{ steps.calculate-next-desktop-version.outputs.version }}" >> $GITHUB_OUTPUT
fi
if [[ "${{ steps.bump-web-version-override.outcome }}" = "success" ]]; then
echo "version_web=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
elif [[ "${{ steps.bump-web-version-automatic.outcome }}" = "success" ]]; then
echo "version=${{ steps.calculate-next-web-version.outputs.version }}" >> $GITHUB_OUTPUT
echo "version_web=${{ steps.calculate-next-web-version.outputs.version }}" >> $GITHUB_OUTPUT
fi
- name: Check if version changed

View File

@ -0,0 +1,26 @@
{
"env": {
"browser": true,
"webextensions": true
},
"overrides": [
{
"files": ["src/**/*.ts"],
"excludedFiles": [
"src/**/{content,popup,spec}/**/*.ts",
"src/**/autofill/{notification,overlay}/**/*.ts",
"src/**/autofill/**/{autofill-overlay-content,collect-autofill-content,dom-element-visibility,insert-autofill-content}.service.ts",
"src/**/*.spec.ts"
],
"rules": {
"no-restricted-globals": [
"error",
{
"name": "window",
"message": "The `window` object is not available in service workers and may not be available within the background script. Consider using `self`, `globalThis`, or another global property instead."
}
]
}
}
]
}

View File

@ -1,6 +1,6 @@
{
"name": "@bitwarden/browser",
"version": "2024.3.0",
"version": "2024.3.1",
"scripts": {
"build": "webpack",
"build:mv3": "cross-env MANIFEST_VERSION=3 webpack",

View File

@ -2386,12 +2386,6 @@
"message": "الاتحاد الأوروبي",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "AB",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Müraciət rədd edildi. Bu səhifəyə baxmaq üçün icazəniz yoxdur."
},

View File

@ -2386,12 +2386,6 @@
"message": "ЕС",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Доступ забаронены. У вас не дастаткова правоў для прагляду гэтай старонкі."
},

View File

@ -2386,12 +2386,6 @@
"message": "ЕС",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Отказан достъп. Нямате право за преглед на страницата."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "UE",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Accés denegat. No teniu permís per veure aquesta pàgina."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Přístup byl odepřen. Nemáte oprávnění k zobrazení této stránky."
},

View File

@ -2386,12 +2386,6 @@
"message": "UE",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Mynediad wedi ei wrthod. Does gennych chi ddim caniatâd i weld y dudalen hon."
},

View File

@ -709,7 +709,7 @@
"message": "Vis indstillinger i kontekstmenuen"
},
"contextMenuItemDesc": {
"message": "Brug et sekundært klik for at få adgang til adgangskodegenerering og matchende logins til hjemmesiden."
"message": "Brug et sekundært klik for at tilgå adgangskodegenerering og matchende logins til webstedet."
},
"contextMenuItemDescAlt": {
"message": "Brug et sekundært klik for at få adgang til adgangskodegenerering og matchende logins til webstedet. Gælder alle indloggede konti."
@ -1033,7 +1033,7 @@
"message": "Server URL"
},
"apiUrl": {
"message": "API server URL"
"message": "API-server URL"
},
"webVaultUrl": {
"message": "Web-boks server URL"
@ -1574,7 +1574,7 @@
"message": "Advarsel: Dette er en ikke-sikret HTTP side, og alle indsendte oplysninger kan potentielt ses og ændres af andre. Dette login blev oprindeligt gemt på en sikker (HTTPS) side."
},
"insecurePageWarningFillPrompt": {
"message": "Do you still wish to fill this login?"
"message": "Ønsker dette login stadig udfyldt?"
},
"autofillIframeWarning": {
"message": "Formularen hostes af et andet domæne end URI'en for det gemte login. Vælg OK for at autoudfylde alligevel, eller Afbryd for at stoppe."
@ -1712,7 +1712,7 @@
"message": "Biometri mislykkedes"
},
"biometricsFailedDesc": {
"message": "Biometri kan ikke fuldføres, overvej at bruge en hovedadgangskode eller logge ud og ind igen. Fortsætter problemet, kontakt Bitwarden-supporten."
"message": "Biometri kan ikke gennemføres. Overvej at bruge en hovedadgangskode eller at logge ud. Fortsætter problemet, kontakt Bitwarden-supporten."
},
"nativeMessaginPermissionErrorTitle": {
"message": "Tilladelse ikke givet"
@ -2027,7 +2027,7 @@
"message": "Minutter"
},
"vaultTimeoutPolicyInEffect": {
"message": "Organisationspolitikker har sat maks. tilladt boks-timeout. til $HOURS$ time(r) og $MINUTES$ minut(ter).",
"message": "Organisationspolitikkerne har fastsat den maksimalt tilladte boks-timeout til $HOURS$ time(r) og $MINUTES$ minut(ter).",
"placeholders": {
"hours": {
"content": "$1",
@ -2314,7 +2314,7 @@
"message": "Sådan autoudfyldes"
},
"autofillSelectInfoWithCommand": {
"message": "Select an item from this screen, use the shortcut $COMMAND$, or explore other options in settings.",
"message": "Vælg et emne fra denne skærm, brug genvejen $COMMAND$ eller udforsk andre valgmuligheder i Indstillinger.",
"placeholders": {
"command": {
"content": "$1",
@ -2323,7 +2323,7 @@
}
},
"autofillSelectInfoWithoutCommand": {
"message": "Select an item from this screen, or explore other options in settings."
"message": "Vælg et emne fra denne skærm eller udforsk andre valgmuligheder i Indstillinger."
},
"gotIt": {
"message": "Forstået"
@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Adgang nægtet. Nødvendig tilladelse til at se siden mangler."
},
@ -2706,7 +2700,7 @@
}
},
"launchDuoAndFollowStepsToFinishLoggingIn": {
"message": "Start DUO og følg trinene for at fuldføre indlogningen."
"message": "Start Duo og følg trinnene for at fuldføre indlogningen."
},
"duoRequiredForAccount": {
"message": "Duo-totrinsindlogning kræves for kontoen."
@ -2718,7 +2712,7 @@
"message": "Pop ud-udvidelse"
},
"launchDuo": {
"message": "Start DUO"
"message": "Start Duo"
},
"importFormatError": {
"message": "Data er ikke korrekt formateret. Tjek importfilen og forsøg igen."

View File

@ -327,7 +327,7 @@
"message": "Passwort"
},
"totp": {
"message": "Authenticator secret"
"message": "Authentifikator-Geheimnis"
},
"passphrase": {
"message": "Passphrase"
@ -522,16 +522,16 @@
"message": "Die Felder dieser Seite konnten nicht automatisch ausgefüllt werden. Bitte Nutzernamen und/oder Passwort manuell kopieren."
},
"totpCaptureError": {
"message": "Unable to scan QR code from the current webpage"
"message": "QR-Code kann nicht von der aktuellen Webseite gescannt werden"
},
"totpCaptureSuccess": {
"message": "Authenticator key added"
"message": "Authentifizierungsschlüssel hinzugefügt"
},
"totpCapture": {
"message": "Scan authenticator QR code from current webpage"
"message": "Den Authentifizierungs-QR-Code von der aktuellen Webseite scannen"
},
"copyTOTP": {
"message": "Copy Authenticator key (TOTP)"
"message": "Authentifizierungsschlüssel kopieren (TOTP)"
},
"loggedOut": {
"message": "Ausgeloggt"
@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Zugriff verweigert. Du hast keine Berechtigung, diese Seite anzuzeigen."
},

View File

@ -2386,12 +2386,6 @@
"message": "ΕΕ",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Δεν επιτρέπεται η πρόσβαση. Δεν έχετε άδεια για να δείτε αυτή τη σελίδα."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},
@ -3005,5 +2999,11 @@
"saveCipherAttemptFailed": {
"message": "Error saving credentials. Check console for details.",
"description": "Notification message for when saving credentials has failed."
},
"removePasskey": {
"message": "Remove passkey"
},
"passkeyRemoved": {
"message": "Passkey removed"
}
}

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "Unión Europea",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Acceso denegado. No tiene permiso para ver esta página."
},

View File

@ -2386,12 +2386,6 @@
"message": "EL",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Ligipääs keelatud. Sul pole lubatud seda lehekülge vaadata."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "اروپا",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "دسترسی رد شد. شما اجازه مشاهده این صفحه را ندارید."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Pääsy estetty. Sinulla ei ole oikeutta avata sivua."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -95,7 +95,7 @@
"message": "Saisie automatique de l'identifiant"
},
"autoFillCard": {
"message": "Saisie automatique de la carte"
"message": "Saisie automatique de la carte de paiement"
},
"autoFillIdentity": {
"message": "Saisie automatique de l'identité"
@ -110,7 +110,7 @@
"message": "Aucun identifiant correspondant"
},
"noCards": {
"message": "Aucune carte"
"message": "Aucune carte de paiement"
},
"noIdentities": {
"message": "Aucune identité"
@ -119,7 +119,7 @@
"message": "Ajouter un identifiant"
},
"addCardMenu": {
"message": "Ajouter une carte"
"message": "Ajouter une carte de paiement"
},
"addIdentityMenu": {
"message": "Ajouter une identité"
@ -131,7 +131,7 @@
"message": "Connectez-vous à votre coffre"
},
"autoFillInfo": {
"message": "Il n'y a pas d'identifiants disponibles pour la saisie automatique dans l'onglet actuel."
"message": "Il n'y a pas d'identifiants disponibles pour la saisie automatique de l'onglet actuel du navigateur."
},
"addLogin": {
"message": "Ajouter un identifiant"
@ -223,7 +223,7 @@
"message": "Centre d'aide Bitwarden"
},
"communityForums": {
"message": "Explorez les forums de la communauté Bitwarden"
"message": "Explorer les forums de la communauté Bitwarden"
},
"contactSupport": {
"message": "Contacter le support Bitwarden"
@ -312,7 +312,7 @@
"message": "Modifier"
},
"view": {
"message": "Voir"
"message": "Afficher"
},
"noItemsInList": {
"message": "Aucun identifiant à afficher."
@ -327,7 +327,7 @@
"message": "Mot de passe"
},
"totp": {
"message": "Application d'authentification"
"message": "Secret de l'Authentificateur"
},
"passphrase": {
"message": "Phrase de passe"
@ -360,7 +360,7 @@
"message": "Site web"
},
"toggleVisibility": {
"message": "Afficher/Masquer"
"message": "Permuter la visibilité"
},
"manage": {
"message": "Gérer"
@ -522,16 +522,16 @@
"message": "Impossible de saisir automatiquement l'élément sélectionné sur cette page. Essayez plutôt le copier-coller."
},
"totpCaptureError": {
"message": "Impossible de scanner le code QR à partir de la page web actuelle"
"message": "Impossible de scanner le QR code à partir de la page web actuelle"
},
"totpCaptureSuccess": {
"message": "Clé d'authentification ajoutée"
"message": "Clé de l'Authentificateur ajoutée"
},
"totpCapture": {
"message": "Scanner le code QR à partir de la page web actuelle"
"message": "Scanner le QR code de l'authentificateur à partir de la page web actuelle"
},
"copyTOTP": {
"message": "Copier la clé TOTP"
"message": "Copier la clé de l'Authentificateur (TOTP)"
},
"loggedOut": {
"message": "Déconnecté"
@ -644,25 +644,25 @@
"description": "This is the folder for uncategorized items"
},
"enableAddLoginNotification": {
"message": "Demander à ajouter un identifiant"
"message": "Demander d'ajouter un identifiant"
},
"addLoginNotificationDesc": {
"message": "Demander à ajouter un élément si aucun n'est trouvé dans votre coffre."
"message": "Demander d'ajouter un élément si aucun n'est trouvé dans votre coffre."
},
"addLoginNotificationDescAlt": {
"message": "Demandez d'ajouter un élément s'il celui-ci n'est pas trouvé dans votre coffre. S'applique à tous les comptes connectés."
"message": "Demande l'ajout d'un élément si celui-ci n'est pas trouvé dans votre coffre. S'applique à tous les comptes connectés."
},
"showCardsCurrentTab": {
"message": "Afficher les cartes de paiement sur page d'Onglet"
"message": "Afficher les cartes de paiement sur la Page d'onglet"
},
"showCardsCurrentTabDesc": {
"message": "Lister les éléments de la carte sur la page de l'onglet pour faciliter la saisie automatique."
"message": "Liste les éléments des cartes de paiement sur la Page d'onglet pour faciliter la saisie automatique."
},
"showIdentitiesCurrentTab": {
"message": "Afficher les identités sur page d'Onglet"
"message": "Afficher les identités sur la page d'onglet"
},
"showIdentitiesCurrentTabDesc": {
"message": "Lister les éléments d'identité sur la page de l'onglet pour faciliter la saisie automatique."
"message": "Liste les éléments d'identité sur la Page d'onglet pour faciliter la saisie automatique."
},
"clearClipboard": {
"message": "Effacer le presse-papiers",
@ -679,19 +679,19 @@
"message": "Enregistrer"
},
"enableChangedPasswordNotification": {
"message": "Demander à mettre à jour un identifiant existant"
"message": "Demander de mettre à jour un identifiant existant"
},
"changedPasswordNotificationDesc": {
"message": "Demander à mettre à jour le mot de passe d'un identifiant lorsqu'un changement est détecté sur un site Web."
"message": "Demande la mise à jour du mot de passe d'un identifiant lorsqu'un changement est détecté sur un site Web."
},
"changedPasswordNotificationDescAlt": {
"message": "Demander à mettre à jour le mot de passe d'un identifiant lorsqu'un changement est détecté sur un site web. S'applique à tous les comptes connectés."
"message": "Demande la mise à jour du mot de passe d'un identifiant lorsqu'un changement est détecté sur un site web. S'applique à tous les comptes connectés."
},
"enableUsePasskeys": {
"message": "Demander à enregistrer et utiliser les clés d'accès"
"message": "Demander d'enregistrer et d'utiliser les clés d'identification (passkeys)"
},
"usePasskeysDesc": {
"message": "Demander d'enregistrer de nouvelles clés d'accès ou bien de se connecter à l'aide de clés stockées dans votre coffre. S'applique à tous les comptes connectés."
"message": "Demande l'enregistrement de nouvelles clés d'identification (passkeys) ou la connexion à l'aide des clés d'identification (passkeys) stockées dans votre coffre. S'applique à tous les comptes connectés."
},
"notificationChangeDesc": {
"message": "Souhaitez-vous mettre à jour ce mot de passe dans Bitwarden ?"
@ -719,7 +719,7 @@
"description": "Default URI match detection for auto-fill."
},
"defaultUriMatchDetectionDesc": {
"message": "Choisissez la manière de gestion par défaut de la détection de correspondance URI pour les identifiants lors de l'exécution d'actions telles que la saisie automatique."
"message": "Choisit la manière dont la détection des correspondances URI est gérée par défaut pour les connexions lors d'actions telles que la saisie automatique."
},
"theme": {
"message": "Thème"
@ -802,7 +802,7 @@
"message": "En savoir plus"
},
"authenticatorKeyTotp": {
"message": "Clé d'authentification (TOTP)"
"message": "Clé de l'Authentificateur (TOTP)"
},
"verificationCodeTotp": {
"message": "Code de vérification (TOTP)"
@ -841,7 +841,7 @@
"message": "La taille maximale du fichier est de 500 Mo."
},
"featureUnavailable": {
"message": "Fonctionnalité non disponible"
"message": "Fonctionnalité indisponible"
},
"encryptionKeyMigrationRequired": {
"message": "Migration de la clé de chiffrement nécessaire. Veuillez vous connecter sur le coffre web pour mettre à jour votre clé de chiffrement."
@ -907,7 +907,7 @@
"message": "Actualisation terminée"
},
"enableAutoTotpCopy": {
"message": "Copier TOTP automatiquement"
"message": "Copier le TOTP automatiquement"
},
"disableAutoTotpCopyDesc": {
"message": "Si un identifiant possède une clé d'authentification, copie le code de vérification TOTP dans votre presse-papiers lorsque vous saisissez automatiquement l'identifiant."
@ -967,7 +967,7 @@
"message": "Authentifier WebAuthn"
},
"loginUnavailable": {
"message": "Identifiant non disponible"
"message": "Identifiant indisponible"
},
"noTwoStepProviders": {
"message": "Ce compte dispose d'une authentification à deux facteurs de configurée, cependant, aucun des fournisseurs à deux facteurs configurés n'est pris en charge par ce navigateur web."
@ -1887,7 +1887,7 @@
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendShareDesc": {
"message": "Copier dans le presse-papiers le lien de ce Send lors de l'enregistrement.",
"message": "Copier le lien de ce Send dans le presse-papiers lors de l'enregistrement.",
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
},
"sendTextDesc": {
@ -2166,7 +2166,7 @@
"message": "Service"
},
"forwardedEmail": {
"message": "Alias d'email transféré"
"message": "Alias de courriel transféré"
},
"forwardedEmailDesc": {
"message": "Générer un alias de courriel avec un service de transfert externe."
@ -2386,12 +2386,6 @@
"message": "UE",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Accès refusé. Vous n'avez pas l'autorisation de voir cette page."
},
@ -2792,55 +2786,55 @@
"message": "Confirmez le mot de passe du fichier"
},
"typePasskey": {
"message": "Clé d'accès"
"message": "Clé d'identification (passkey)"
},
"passkeyNotCopied": {
"message": "La clé d'accès ne sera pas copiée"
"message": "La clé d'identification (passkey) ne sera pas copiée"
},
"passkeyNotCopiedAlert": {
"message": "La clé d'accès ne sera pas présente sur l'entrée clonée. Continuer quand même ?"
"message": "La clé d'identification (passkey) ne sera pas copiée dans l'élément cloné. Voulez-vous continuer à cloner cet élément ?"
},
"passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": {
"message": "Le site requiert une vérification qui n'est pas supportée pour les comptes sans mot de passe maître."
"message": "Vérification requise par le site initiateur. Cette fonctionnalité n'est pas encore implémentée pour les comptes sans mot de passe principal."
},
"logInWithPasskey": {
"message": "Se connecter avec une clé d'accès ?"
"message": "Se connecter avec une clé d'identification (passkey) ?"
},
"passkeyAlreadyExists": {
"message": "Une clé d'accès existe déjà pour cette application."
"message": "Une clé d'identification (passkey) existe déjà pour cette application."
},
"noPasskeysFoundForThisApplication": {
"message": "Aucune clé d'accès trouvée pour cette application."
"message": "Aucune clé d'identification (passkey) trouvée pour cette application."
},
"noMatchingPasskeyLogin": {
"message": "Vous n'avez aucun élément correspondant à ce site."
"message": "Vous n'avez pas d'identifiant correspondant à ce site."
},
"confirm": {
"message": "Confirmer"
},
"savePasskey": {
"message": "Enregistrer la clé d'accès"
"message": "Enregistrer la clé d'identification (passkey)"
},
"savePasskeyNewLogin": {
"message": "Enregistrer comme nouvel élément"
"message": "Enregistrer la clé d'identification (passkey) comme nouvel identifiant"
},
"choosePasskey": {
"message": "Choisissez l'élément à associer à la clé d'accès"
"message": "Choisissez cette clé d'identification (passkey) pour l'enregistrer avec cet identifiant"
},
"passkeyItem": {
"message": "Élément avec clé d'accès"
"message": "Élément clé d'identification (passkey)"
},
"overwritePasskey": {
"message": "Écraser la clé d'accès existante ?"
"message": "Écraser la clé d'identification (passkey) ?"
},
"overwritePasskeyAlert": {
"message": "Cet élément contient déjà une clé d'accès. Voulez-vous vraiment l'écraser ?"
"message": "Cet élément contient déjà une clé d'identification (passkey). Êtes-vous sûr de vouloir écraser la clé d'identification (passkey) actuelle ?"
},
"featureNotSupported": {
"message": "Fonctionnalité non supportée"
},
"yourPasskeyIsLocked": {
"message": "Authentification requise pour utiliser cette clé d'accès. Veuillez vérifier votre identité pour continuer."
"message": "Authentification requise pour utiliser une clé d'identification (passkey). Vérifiez votre identité pour continuer."
},
"multifactorAuthenticationCancelled": {
"message": "Authentification multi-facteurs annulée"
@ -2995,15 +2989,15 @@
"description": "Button text for the setting that allows overriding the default browser autofill settings"
},
"saveCipherAttemptSuccess": {
"message": "Credentials saved successfully!",
"message": "Identifiants enregistrés avec succès !",
"description": "Notification message for when saving credentials has succeeded."
},
"updateCipherAttemptSuccess": {
"message": "Credentials updated successfully!",
"message": "Identifiants mis à jour avec succès !",
"description": "Notification message for when updating credentials has succeeded."
},
"saveCipherAttemptFailed": {
"message": "Error saving credentials. Check console for details.",
"message": "Erreur lors de l'enregistrement des identifiants. Consultez la console pour plus de détails.",
"description": "Notification message for when saving credentials has failed."
}
}

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Pristup odbijen. Nemaš prava vidjeti ovu stranicu."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "A hozzáférés megtagadásra került. Nincs jogosultság az oldal megtekintésére."
},

View File

@ -20,7 +20,7 @@
"message": "Masuk"
},
"enterpriseSingleSignOn": {
"message": "Sistem Masuk Tunggal Perusahaan"
"message": "SSO Perusahaan"
},
"cancel": {
"message": "Batal"
@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Accesso negato. Non hai i permessi necessari per visualizzare questa pagina."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "アクセスが拒否されました。このページを表示する権限がありません。"
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "ES",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Prieiga uždrausta. Neturi teisės peržiūrėti šį puslapį."
},

View File

@ -2386,12 +2386,6 @@
"message": "ES",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Piekļuve liegta. Nav nepieciešamo atļauju, lai skatītu šo lapu."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Toegang geweigerd. Je hebt geen toestemming om deze pagina te bekijken."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "UE",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Odmowa dostępu. Nie masz uprawnień do przeglądania tej strony."
},

View File

@ -2386,12 +2386,6 @@
"message": "Europa",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Acesso negado. Você não tem permissão para ver esta página."
},

View File

@ -2386,12 +2386,6 @@
"message": "UE",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Acesso negado. Não tem permissão para visualizar esta página."
},
@ -2919,7 +2913,7 @@
"message": "Mudar de conta"
},
"switchAccounts": {
"message": "Mudar de contas"
"message": "Mudar de conta"
},
"switchToAccount": {
"message": "Mudar para conta"

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Acces refuzat. Nu aveți permisiunea de a vizualiza această pagină."
},

View File

@ -2386,12 +2386,6 @@
"message": "Европа",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Доступ запрещен. У вас нет разрешения на просмотр этой страницы."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EÚ",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Prístup zamietnutý. Nemáte oprávnenie na zobrazenie tejto stránky."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Одбијен приступ. Немате дозволу да видите ову страницу."
},

View File

@ -494,7 +494,7 @@
"message": "Ditt nya konto har skapats! Du kan logga in nu."
},
"youSuccessfullyLoggedIn": {
"message": "You successfully logged in"
"message": "Du är nu inloggad"
},
"youMayCloseThisWindow": {
"message": "Du kan stänga detta fönster"
@ -522,7 +522,7 @@
"message": "Kunde inte automatiskt fylla i det valda objektet på den här webbsidan. Klipp/klistra informationen istället."
},
"totpCaptureError": {
"message": "Unable to scan QR code from the current webpage"
"message": "Det går inte att skanna QR-koden från den aktuella webbsidan"
},
"totpCaptureSuccess": {
"message": "Authenticator key added"
@ -868,7 +868,7 @@
"message": "1 GB lagring av krypterade filer."
},
"premiumSignUpTwoStepOptions": {
"message": "Proprietary two-step login options such as YubiKey and Duo."
"message": "Premium-alternativ för tvåstegsverifiering, såsom YubiKey och Duo."
},
"ppremiumSignUpReports": {
"message": "Lösenordshygien, kontohälsa och dataintrångsrapporter för att hålla ditt valv säkert."
@ -1993,7 +1993,7 @@
"message": "Ditt huvudlösenord ändrades nyligen av en administratör i din organisation. För att få tillgång till valvet måste du uppdatera det nu. Om du fortsätter kommer du att loggas ut från din nuvarande session, vilket kräver att du loggar in igen. Aktiva sessioner på andra enheter kan komma att vara aktiva i upp till en timme."
},
"updateWeakMasterPasswordWarning": {
"message": "Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour."
"message": "Ditt huvudlösenord följer inte ett eller flera av din organisations regler. För att komma åt ditt valv så måste du ändra ditt huvudlösenord nu. Om du gör det kommer du att loggas du ut ur din nuvarande session så du måste logga in på nytt. Aktiva sessioner på andra enheter kommer fortsatt vara aktiva i upp till en timme."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatiskt deltagande"
@ -2009,11 +2009,11 @@
"description": "Used as a message within the notification bar when no folders are found"
},
"orgPermissionsUpdatedMustSetPassword": {
"message": "Your organization permissions were updated, requiring you to set a master password.",
"message": "Din organisations behörigheter uppdaterades, vilket kräver att du anger ett huvudlösenord.",
"description": "Used as a card title description on the set password page to explain why the user is there"
},
"orgRequiresYouToSetPassword": {
"message": "Your organization requires you to set a master password.",
"message": "Din organisation kräver att du anger ett huvudlösenord.",
"description": "Used as a card title description on the set password page to explain why the user is there"
},
"verificationRequired": {
@ -2215,7 +2215,7 @@
"message": "Serverversion"
},
"selfHostedServer": {
"message": "self-hosted"
"message": "självhostad"
},
"thirdParty": {
"message": "Tredje part"
@ -2371,7 +2371,7 @@
"message": "Uncheck if using a public device"
},
"approveFromYourOtherDevice": {
"message": "Approve from your other device"
"message": "Godkänn från din andra enhet"
},
"requestAdminApproval": {
"message": "Be om godkännande från administratör"
@ -2380,18 +2380,12 @@
"message": "Godkänn med huvudlösenord"
},
"ssoIdentifierRequired": {
"message": "Organization SSO identifier is required."
"message": "Organisationens SSO-identifierare krävs."
},
"eu": {
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},
@ -2402,10 +2396,10 @@
"message": "Display"
},
"accountSuccessfullyCreated": {
"message": "Account successfully created!"
"message": "Ditt konto har skapats!"
},
"adminApprovalRequested": {
"message": "Admin approval requested"
"message": "Godkännande från administratör har begärts"
},
"adminApprovalRequestSentToAdmins": {
"message": "Din begäran har skickats till din administratör."
@ -2420,13 +2414,13 @@
"message": "Inloggning godkänd"
},
"userEmailMissing": {
"message": "User email missing"
"message": "Användarens e-postadress saknas"
},
"deviceTrusted": {
"message": "Device trusted"
},
"inputRequired": {
"message": "Input is required."
"message": "Inmatning är obligatoriskt."
},
"required": {
"message": "obligatoriskt"
@ -2526,7 +2520,7 @@
"message": "Undermeny"
},
"toggleCollapse": {
"message": "Toggle collapse",
"message": "Växla synlig/dold",
"description": "Toggling an expand/collapse state."
},
"filelessImport": {
@ -2550,7 +2544,7 @@
"description": "Notification message for when an import is in progress."
},
"dataSuccessfullyImported": {
"message": "Data successfully imported!",
"message": "Data har importerats till ditt valv!",
"description": "Notification message for when an import has completed successfully."
},
"dataImportFailed": {
@ -2577,7 +2571,7 @@
"description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item."
},
"skipToContent": {
"message": "Skip to content"
"message": "Hoppa till innehåll"
},
"bitwardenOverlayButton": {
"message": "Bitwarden automatisk ifyllnadsmenyknapp",
@ -2596,11 +2590,11 @@
"description": "Text to display in overlay when the account is locked."
},
"unlockAccount": {
"message": "Unlock account",
"message": "Lås upp konto",
"description": "Button text to display in overlay when the account is locked."
},
"fillCredentialsFor": {
"message": "Fill credentials for",
"message": "Fyll i uppgifter för",
"description": "Screen reader text for when overlay item is in focused"
},
"partialUsername": {
@ -2624,7 +2618,7 @@
"description": "Screen reader text for announcing when the overlay opens on the page"
},
"turnOn": {
"message": "Turn on"
"message": "Aktivera"
},
"ignore": {
"message": "Ignorera"
@ -2634,7 +2628,7 @@
"description": "Used for the header of the import dialog, the import button and within the file-password-prompt"
},
"importError": {
"message": "Import error"
"message": "Fel vid import"
},
"importErrorDesc": {
"message": "Det uppstod ett problem med den data du försökte importera. Åtgärda de fel som anges nedan i din källfil och försök igen."
@ -2646,10 +2640,10 @@
"message": "Beskrivning"
},
"importSuccess": {
"message": "Data successfully imported"
"message": "Data har importerats till ditt valv"
},
"importSuccessNumberOfItems": {
"message": "A total of $AMOUNT$ items were imported.",
"message": "Sammanlagt $AMOUNT$ objekt importerades.",
"placeholders": {
"amount": {
"content": "$1",
@ -2670,10 +2664,10 @@
"message": "Verifiera med biometri"
},
"awaitingConfirmation": {
"message": "Awaiting confirmation"
"message": "Väntar på bekräftelse"
},
"couldNotCompleteBiometrics": {
"message": "Could not complete biometrics."
"message": "Det gick inte att slutföra biometri."
},
"needADifferentMethod": {
"message": "Behöver du en annan metod?"
@ -2688,16 +2682,16 @@
"message": "Använd biometri"
},
"enterVerificationCodeSentToEmail": {
"message": "Enter the verification code that was sent to your email."
"message": "Ange verifieringskoden som skickades till din e-postadress."
},
"resendCode": {
"message": "Skicka kod igen"
},
"total": {
"message": "Total"
"message": "Totalt"
},
"importWarning": {
"message": "You are importing data to $ORGANIZATION$. Your data may be shared with members of this organization. Do you want to proceed?",
"message": "Du importerar data till $ORGANIZATION$. Din data kan komma att delas med medlemmar i den här organisationen. Vill du fortsätta?",
"placeholders": {
"organization": {
"content": "$1",
@ -2718,19 +2712,19 @@
"message": "Popout extension"
},
"launchDuo": {
"message": "Launch Duo"
"message": "Starta Duo"
},
"importFormatError": {
"message": "Data is not formatted correctly. Please check your import file and try again."
"message": "Datan är inte korrekt formaterad. Vänligen kontrollera din importerade fil och försök igen."
},
"importNothingError": {
"message": "Ingenting har importerats."
},
"importEncKeyError": {
"message": "Error decrypting the exported file. Your encryption key does not match the encryption key used export the data."
"message": "Ett fel uppstod vid dekryptering av den exporterade filen. Din krypteringsnyckel matchar inte krypteringsnyckeln som användes för att exportera datan."
},
"invalidFilePassword": {
"message": "Invalid file password, please use the password you entered when you created the export file."
"message": "Ogiltigt fillösenord, använd lösenordet du angav när du skapade exportfilen."
},
"importDestination": {
"message": "Importdestination"
@ -2755,13 +2749,13 @@
}
},
"importUnassignedItemsError": {
"message": "File contains unassigned items."
"message": "Filen innehåller otilldelade objekt."
},
"selectFormat": {
"message": "Select the format of the import file"
"message": "Välj importfilens format"
},
"selectImportFile": {
"message": "Select the import file"
"message": "Välj importfilen"
},
"chooseFile": {
"message": "Välj fil"
@ -2770,10 +2764,10 @@
"message": "Ingen fil vald"
},
"orCopyPasteFileContents": {
"message": "or copy/paste the import file contents"
"message": "eller kopiera och klistra in innehållet från filen"
},
"instructionsFor": {
"message": "$NAME$ Instructions",
"message": "Instruktioner för $NAME$",
"description": "The title for the import tool instructions.",
"placeholders": {
"name": {
@ -2783,13 +2777,13 @@
}
},
"confirmVaultImport": {
"message": "Confirm vault import"
"message": "Bekräfta importering av valv"
},
"confirmVaultImportDesc": {
"message": "This file is password-protected. Please enter the file password to import data."
"message": "Den här filen är lösenordsskyddad. Ange lösenordet för att importera data."
},
"confirmFilePassword": {
"message": "Confirm file password"
"message": "Bekräfta fillösenord"
},
"typePasskey": {
"message": "Lösennyckel"
@ -2837,7 +2831,7 @@
"message": "Detta objekt innehåller redan en lösennyckel. Är du säker på att du vill skriva över nuvarande lösennyckeln?"
},
"featureNotSupported": {
"message": "Feature not yet supported"
"message": "Funktionen stöds ännu inte"
},
"yourPasskeyIsLocked": {
"message": "Autentisering krävs för att använda lösennyckel. Verifiera din identitet för att fortsätta."
@ -2913,19 +2907,19 @@
"message": "Samling"
},
"lastPassYubikeyDesc": {
"message": "Insert the YubiKey associated with your LastPass account into your computer's USB port, then touch its button."
"message": "Sätt in YubiKey som associeras med ditt LastPass-konto i din dators USB-port, tryck sedan på knappen."
},
"switchAccount": {
"message": "Switch account"
"message": "Byt konto"
},
"switchAccounts": {
"message": "Switch accounts"
"message": "Byt konto"
},
"switchToAccount": {
"message": "Switch to account"
"message": "Byt till konto"
},
"activeAccount": {
"message": "Active account"
"message": "Aktivt konto"
},
"availableAccounts": {
"message": "Tillgängliga konton"
@ -2952,10 +2946,10 @@
"message": "Använd din enhet eller hårdvarunyckel"
},
"justOnce": {
"message": "Just once"
"message": "Bara en gång"
},
"alwaysForThisSite": {
"message": "Always for this site"
"message": "Alltid för denna webbplats"
},
"domainAddedToExcludedDomains": {
"message": "$DOMAIN$ added to excluded domains.",
@ -2991,7 +2985,7 @@
"description": "Description for the dialog that appears when the user has not granted the extension permission to set privacy settings"
},
"makeDefault": {
"message": "Make default",
"message": "Gör till standard",
"description": "Button text for the setting that allows overriding the default browser autofill settings"
},
"saveCipherAttemptSuccess": {

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -2386,12 +2386,6 @@
"message": "AB",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Erişim engellendi. Bu sayfayı görüntüleme iznine sahip değilsiniz."
},

View File

@ -2386,12 +2386,6 @@
"message": "ЄС",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Доступ заборонено. У вас немає дозволу на перегляд цієї сторінки."
},

View File

@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@ -1500,7 +1500,7 @@
"message": "无效 PIN 码。"
},
"tooManyInvalidPinEntryAttemptsLoggingOut": {
"message": "无效的 PIN 输入尝试次数过多,正在退出登录。"
"message": "无效的 PIN 输入尝试次数过多,正在注销。"
},
"unlockWithBiometrics": {
"message": "使用生物识别解锁"
@ -1742,7 +1742,7 @@
"message": "Bitwarden 将不会询问是否为这些域名保存登录信息。您必须刷新页面才能使更改生效。"
},
"excludedDomainsDescAlt": {
"message": "Bitwarden 不会询问保存所有已登录的账户的这些域名的登录信息。必须刷新页面才能使更改生效。"
"message": "Bitwarden 不会询问保存所有已登录的账户的这些域名的登录信息。必须刷新页面才能使更改生效。"
},
"excludedDomainsInvalidDomain": {
"message": "$DOMAIN$ 不是一个有效的域名",
@ -2314,7 +2314,7 @@
"message": "如何自动填充"
},
"autofillSelectInfoWithCommand": {
"message": "从此界面选择一个项目,使用快捷方式 $COMMAND$,或探索设置中的其他选项。",
"message": "从此界面选择一个项目,使用快捷 $COMMAND$,或探索设置中的其他选项。",
"placeholders": {
"command": {
"content": "$1",
@ -2335,10 +2335,10 @@
"message": "自动填充键盘快捷键"
},
"autofillShortcutNotSet": {
"message": "未设置自动填充快捷方式。请在浏览器设置中更改此设置。"
"message": "未设置自动填充快捷键。可在浏览器的设置中更改它。"
},
"autofillShortcutText": {
"message": "自动填充快捷方式为: $COMMAND$。在浏览器设置中更改此项。",
"message": "自动填充快捷键为:$COMMAND$。可在浏览器的设置中更改它。",
"placeholders": {
"command": {
"content": "$1",
@ -2386,12 +2386,6 @@
"message": "欧盟",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "访问被拒绝。您没有权限查看此页面。"
},
@ -2934,7 +2928,7 @@
"message": "已达到账户上限。请注销一个账户后再添加其他账户。"
},
"active": {
"message": "已生效"
"message": "活动的"
},
"locked": {
"message": "已锁定"
@ -2967,7 +2961,7 @@
}
},
"commonImportFormats": {
"message": "通用格式",
"message": "常规格式",
"description": "Label indicating the most common import formats"
},
"overrideDefaultBrowserAutofillTitle": {
@ -2975,7 +2969,7 @@
"description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior"
},
"overrideDefaultBrowserAutofillDescription": {
"message": "忽略此设置可能会导致 Bitwarden 自动填充菜单与浏览器自带功能产生冲突。",
"message": "忽略此选项可能会导致 Bitwarden 自动填充菜单与浏览器自带功能产生冲突。",
"description": "Dialog message facilitating the ability to override a chrome browser's default autofill behavior"
},
"overrideDefaultBrowserAutoFillSettings": {

View File

@ -327,7 +327,7 @@
"message": "密碼"
},
"totp": {
"message": "Authenticator secret"
"message": "程式產生驗證碼"
},
"passphrase": {
"message": "密碼短語"
@ -372,7 +372,7 @@
"message": "設定一個解鎖方式來變更您的密碼庫逾時動作。"
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
"message": "設定中設定解鎖"
},
"rateExtension": {
"message": "為本套件評分"
@ -494,10 +494,10 @@
"message": "帳戶已建立!現在可以登入了。"
},
"youSuccessfullyLoggedIn": {
"message": "You successfully logged in"
"message": "登入成功"
},
"youMayCloseThisWindow": {
"message": "You may close this window"
"message": "您可以關閉此視窗"
},
"masterPassSent": {
"message": "已寄出包含您主密碼提示的電子郵件。"
@ -522,13 +522,13 @@
"message": "無法在此頁面自動填入所選項目。請手動複製貼上。"
},
"totpCaptureError": {
"message": "Unable to scan QR code from the current webpage"
"message": "無法掃描此網頁的二維碼"
},
"totpCaptureSuccess": {
"message": "已新增驗證器金鑰。"
},
"totpCapture": {
"message": "Scan authenticator QR code from current webpage"
"message": "從目前網頁掃描驗證器二維碼"
},
"copyTOTP": {
"message": "複製驗證器金鑰 (TOTP)"
@ -1061,7 +1061,7 @@
"message": "Turn off your browsers built in password manager settings to avoid conflicts."
},
"turnOffBrowserBuiltInPasswordManagerSettingsLink": {
"message": "Edit browser settings."
"message": "編輯瀏覽器設定"
},
"autofillOverlayVisibilityOff": {
"message": "關閉",
@ -1500,7 +1500,7 @@
"message": "無效的 PIN 碼。"
},
"tooManyInvalidPinEntryAttemptsLoggingOut": {
"message": "Too many invalid PIN entry attempts. Logging out."
"message": "輸入太多無效 PIN 碼。 登出。"
},
"unlockWithBiometrics": {
"message": "使用生物特徵辨識解鎖"
@ -2005,7 +2005,7 @@
"message": "選擇資料夾⋯"
},
"noFoldersFound": {
"message": "No folders found",
"message": "未找到資料夾",
"description": "Used as a message within the notification bar when no folders are found"
},
"orgPermissionsUpdatedMustSetPassword": {
@ -2017,7 +2017,7 @@
"description": "Used as a card title description on the set password page to explain why the user is there"
},
"verificationRequired": {
"message": "Verification required",
"message": "需要驗證",
"description": "Default title for the user verification dialog."
},
"hours": {
@ -2386,12 +2386,6 @@
"message": "EU",
"description": "European Union"
},
"usDomain": {
"message": "bitwarden.com"
},
"euDomain": {
"message": "bitwarden.eu"
},
"accessDenied": {
"message": "拒絕存取。您沒有檢視此頁面的權限。"
},
@ -2558,7 +2552,7 @@
"description": "Notification message for when an import has failed."
},
"importNetworkError": {
"message": "Network error encountered during import.",
"message": "匯入時遇到網路錯誤",
"description": "Notification message for when an import has failed due to a network error."
},
"aliasDomain": {
@ -2664,34 +2658,34 @@
"message": "Verification required for this action. Set a PIN to continue."
},
"setPin": {
"message": "Set PIN"
"message": "設定 PIN 碼"
},
"verifyWithBiometrics": {
"message": "Verify with biometrics"
"message": "生物辨識驗證"
},
"awaitingConfirmation": {
"message": "Awaiting confirmation"
"message": "正在等待確認"
},
"couldNotCompleteBiometrics": {
"message": "Could not complete biometrics."
},
"needADifferentMethod": {
"message": "Need a different method?"
"message": "需要不同的方法嗎?"
},
"useMasterPassword": {
"message": "Use master password"
"message": "用主密碼"
},
"usePin": {
"message": "Use PIN"
"message": "使用 PIN 碼"
},
"useBiometrics": {
"message": "Use biometrics"
"message": "用生物識別"
},
"enterVerificationCodeSentToEmail": {
"message": "Enter the verification code that was sent to your email."
},
"resendCode": {
"message": "Resend code"
"message": "重新傳送驗證碼"
},
"total": {
"message": "總計"
@ -2718,7 +2712,7 @@
"message": "Popout extension"
},
"launchDuo": {
"message": "Launch Duo"
"message": "開啟Duo"
},
"importFormatError": {
"message": "資料格式不正確。請檢查您匯入的檔案後再試一次。"
@ -2852,13 +2846,13 @@
"message": "使用者名稱或密碼不正確"
},
"incorrectPassword": {
"message": "Incorrect password"
"message": "密碼錯誤"
},
"incorrectCode": {
"message": "Incorrect code"
"message": "錯誤驗證碼"
},
"incorrectPin": {
"message": "Incorrect PIN"
"message": "PIN 碼錯誤"
},
"multifactorAuthenticationFailed": {
"message": "多因素驗證失敗"
@ -2919,7 +2913,7 @@
"message": "切換帳戶"
},
"switchAccounts": {
"message": "Switch accounts"
"message": "切換帳號"
},
"switchToAccount": {
"message": "切換帳戶"
@ -2991,7 +2985,7 @@
"description": "Description for the dialog that appears when the user has not granted the extension permission to set privacy settings"
},
"makeDefault": {
"message": "Make default",
"message": "設為預設",
"description": "Button text for the setting that allows overriding the default browser autofill settings"
},
"saveCipherAttemptSuccess": {

View File

@ -15,21 +15,26 @@ import {
factory,
} from "../../../platform/background/service-factories/factory-options";
import {
messagingServiceFactory,
MessagingServiceInitOptions,
messagingServiceFactory,
} from "../../../platform/background/service-factories/messaging-service.factory";
import {
StateServiceInitOptions,
stateServiceFactory,
} from "../../../platform/background/service-factories/state-service.factory";
import { AccountServiceInitOptions, accountServiceFactory } from "./account-service.factory";
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
type AuthServiceFactoryOptions = FactoryOptions;
export type AuthServiceInitOptions = AuthServiceFactoryOptions &
AccountServiceInitOptions &
MessagingServiceInitOptions &
CryptoServiceInitOptions &
ApiServiceInitOptions &
StateServiceInitOptions;
StateServiceInitOptions &
TokenServiceInitOptions;
export function authServiceFactory(
cache: { authService?: AbstractAuthService } & CachedServices,
@ -41,10 +46,12 @@ export function authServiceFactory(
opts,
async () =>
new AuthService(
await accountServiceFactory(cache, opts),
await messagingServiceFactory(cache, opts),
await cryptoServiceFactory(cache, opts),
await apiServiceFactory(cache, opts),
await stateServiceFactory(cache, opts),
await tokenServiceFactory(cache, opts),
),
);
}

View File

@ -39,9 +39,18 @@ import {
platformUtilsServiceFactory,
} from "../../../platform/background/service-factories/platform-utils-service.factory";
import {
StateServiceInitOptions,
stateServiceFactory,
} from "../../../platform/background/service-factories/state-service.factory";
StateProviderInitOptions,
stateProviderFactory,
} from "../../../platform/background/service-factories/state-provider.factory";
import {
SecureStorageServiceInitOptions,
secureStorageServiceFactory,
} from "../../../platform/background/service-factories/storage-service.factory";
import {
UserDecryptionOptionsServiceInitOptions,
userDecryptionOptionsServiceFactory,
} from "./user-decryption-options-service.factory";
type DeviceTrustCryptoServiceFactoryOptions = FactoryOptions;
@ -50,11 +59,13 @@ export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactor
CryptoFunctionServiceInitOptions &
CryptoServiceInitOptions &
EncryptServiceInitOptions &
StateServiceInitOptions &
AppIdServiceInitOptions &
DevicesApiServiceInitOptions &
I18nServiceInitOptions &
PlatformUtilsServiceInitOptions;
PlatformUtilsServiceInitOptions &
StateProviderInitOptions &
SecureStorageServiceInitOptions &
UserDecryptionOptionsServiceInitOptions;
export function deviceTrustCryptoServiceFactory(
cache: { deviceTrustCryptoService?: DeviceTrustCryptoServiceAbstraction } & CachedServices,
@ -70,11 +81,13 @@ export function deviceTrustCryptoServiceFactory(
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),
await stateProviderFactory(cache, opts),
await secureStorageServiceFactory(cache, opts),
await userDecryptionOptionsServiceFactory(cache, opts),
),
);
}

View File

@ -27,9 +27,9 @@ import {
LogServiceInitOptions,
} from "../../../platform/background/service-factories/log-service.factory";
import {
stateServiceFactory,
StateServiceInitOptions,
} from "../../../platform/background/service-factories/state-service.factory";
stateProviderFactory,
StateProviderInitOptions,
} from "../../../platform/background/service-factories/state-provider.factory";
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
@ -40,13 +40,13 @@ type KeyConnectorServiceFactoryOptions = FactoryOptions & {
};
export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions &
StateServiceInitOptions &
CryptoServiceInitOptions &
ApiServiceInitOptions &
TokenServiceInitOptions &
LogServiceInitOptions &
OrganizationServiceInitOptions &
KeyGenerationServiceInitOptions;
KeyGenerationServiceInitOptions &
StateProviderInitOptions;
export function keyConnectorServiceFactory(
cache: { keyConnectorService?: AbstractKeyConnectorService } & CachedServices,
@ -58,7 +58,6 @@ export function keyConnectorServiceFactory(
opts,
async () =>
new KeyConnectorService(
await stateServiceFactory(cache, opts),
await cryptoServiceFactory(cache, opts),
await apiServiceFactory(cache, opts),
await tokenServiceFactory(cache, opts),
@ -66,6 +65,7 @@ export function keyConnectorServiceFactory(
await organizationServiceFactory(cache, opts),
await keyGenerationServiceFactory(cache, opts),
opts.keyConnectorServiceOptions.logoutCallback,
await stateProviderFactory(cache, opts),
),
);
}

View File

@ -0,0 +1,28 @@
import { LoginEmailServiceAbstraction, LoginEmailService } from "@bitwarden/auth/common";
import {
CachedServices,
factory,
FactoryOptions,
} from "../../../platform/background/service-factories/factory-options";
import {
stateProviderFactory,
StateProviderInitOptions,
} from "../../../platform/background/service-factories/state-provider.factory";
type LoginEmailServiceFactoryOptions = FactoryOptions;
export type LoginEmailServiceInitOptions = LoginEmailServiceFactoryOptions &
StateProviderInitOptions;
export function loginEmailServiceFactory(
cache: { loginEmailService?: LoginEmailServiceAbstraction } & CachedServices,
opts: LoginEmailServiceInitOptions,
): Promise<LoginEmailServiceAbstraction> {
return factory(
cache,
"loginEmailService",
opts,
async () => new LoginEmailService(await stateProviderFactory(cache, opts)),
);
}

View File

@ -9,7 +9,10 @@ import {
ApiServiceInitOptions,
} from "../../../platform/background/service-factories/api-service.factory";
import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory";
import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
import {
billingAccountProfileStateServiceFactory,
BillingAccountProfileStateServiceInitOptions,
} from "../../../platform/background/service-factories/billing-account-profile-state-service.factory";
import {
CryptoServiceInitOptions,
cryptoServiceFactory,
@ -70,6 +73,10 @@ import {
} from "./key-connector-service.factory";
import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory";
import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory";
import {
internalUserDecryptionOptionServiceFactory,
UserDecryptionOptionsServiceInitOptions,
} from "./user-decryption-options-service.factory";
type LoginStrategyServiceFactoryOptions = FactoryOptions;
@ -90,7 +97,9 @@ export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions
PasswordStrengthServiceInitOptions &
DeviceTrustCryptoServiceInitOptions &
AuthRequestServiceInitOptions &
GlobalStateProviderInitOptions;
UserDecryptionOptionsServiceInitOptions &
GlobalStateProviderInitOptions &
BillingAccountProfileStateServiceInitOptions;
export function loginStrategyServiceFactory(
cache: { loginStrategyService?: LoginStrategyServiceAbstraction } & CachedServices,
@ -119,6 +128,7 @@ export function loginStrategyServiceFactory(
await policyServiceFactory(cache, opts),
await deviceTrustCryptoServiceFactory(cache, opts),
await authRequestServiceFactory(cache, opts),
await internalUserDecryptionOptionServiceFactory(cache, opts),
await globalStateProviderFactory(cache, opts),
await billingAccountProfileStateServiceFactory(cache, opts),
),

View File

@ -1,6 +1,10 @@
import { TokenService as AbstractTokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { TokenService } from "@bitwarden/common/auth/services/token.service";
import {
EncryptServiceInitOptions,
encryptServiceFactory,
} from "../../../platform/background/service-factories/encrypt-service.factory";
import {
FactoryOptions,
CachedServices,
@ -10,6 +14,14 @@ import {
GlobalStateProviderInitOptions,
globalStateProviderFactory,
} from "../../../platform/background/service-factories/global-state-provider.factory";
import {
KeyGenerationServiceInitOptions,
keyGenerationServiceFactory,
} from "../../../platform/background/service-factories/key-generation-service.factory";
import {
LogServiceInitOptions,
logServiceFactory,
} from "../../../platform/background/service-factories/log-service.factory";
import {
PlatformUtilsServiceInitOptions,
platformUtilsServiceFactory,
@ -29,7 +41,10 @@ export type TokenServiceInitOptions = TokenServiceFactoryOptions &
SingleUserStateProviderInitOptions &
GlobalStateProviderInitOptions &
PlatformUtilsServiceInitOptions &
SecureStorageServiceInitOptions;
SecureStorageServiceInitOptions &
KeyGenerationServiceInitOptions &
EncryptServiceInitOptions &
LogServiceInitOptions;
export function tokenServiceFactory(
cache: { tokenService?: AbstractTokenService } & CachedServices,
@ -45,6 +60,9 @@ export function tokenServiceFactory(
await globalStateProviderFactory(cache, opts),
(await platformUtilsServiceFactory(cache, opts)).supportsSecureStorage(),
await secureStorageServiceFactory(cache, opts),
await keyGenerationServiceFactory(cache, opts),
await encryptServiceFactory(cache, opts),
await logServiceFactory(cache, opts),
),
);
}

View File

@ -0,0 +1,46 @@
import {
InternalUserDecryptionOptionsServiceAbstraction,
UserDecryptionOptionsService,
UserDecryptionOptionsServiceAbstraction,
} from "@bitwarden/auth/common";
import {
CachedServices,
factory,
FactoryOptions,
} from "../../../platform/background/service-factories/factory-options";
import {
stateProviderFactory,
StateProviderInitOptions,
} from "../../../platform/background/service-factories/state-provider.factory";
type UserDecryptionOptionsServiceFactoryOptions = FactoryOptions;
export type UserDecryptionOptionsServiceInitOptions = UserDecryptionOptionsServiceFactoryOptions &
StateProviderInitOptions;
export function userDecryptionOptionsServiceFactory(
cache: {
userDecryptionOptionsService?: InternalUserDecryptionOptionsServiceAbstraction;
} & CachedServices,
opts: UserDecryptionOptionsServiceInitOptions,
): Promise<UserDecryptionOptionsServiceAbstraction> {
return factory(
cache,
"userDecryptionOptionsService",
opts,
async () => new UserDecryptionOptionsService(await stateProviderFactory(cache, opts)),
);
}
export async function internalUserDecryptionOptionServiceFactory(
cache: {
userDecryptionOptionsService?: InternalUserDecryptionOptionsServiceAbstraction;
} & CachedServices,
opts: UserDecryptionOptionsServiceInitOptions,
): Promise<InternalUserDecryptionOptionsServiceAbstraction> {
return (await userDecryptionOptionsServiceFactory(
cache,
opts,
)) as InternalUserDecryptionOptionsServiceAbstraction;
}

View File

@ -32,6 +32,10 @@ import {
} from "../../../platform/background/service-factories/state-service.factory";
import { PinCryptoServiceInitOptions, pinCryptoServiceFactory } from "./pin-crypto-service.factory";
import {
userDecryptionOptionsServiceFactory,
UserDecryptionOptionsServiceInitOptions,
} from "./user-decryption-options-service.factory";
import {
UserVerificationApiServiceInitOptions,
userVerificationApiServiceFactory,
@ -44,6 +48,7 @@ export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryO
CryptoServiceInitOptions &
I18nServiceInitOptions &
UserVerificationApiServiceInitOptions &
UserDecryptionOptionsServiceInitOptions &
PinCryptoServiceInitOptions &
LogServiceInitOptions &
VaultTimeoutSettingsServiceInitOptions &
@ -63,6 +68,7 @@ export function userVerificationServiceFactory(
await cryptoServiceFactory(cache, opts),
await i18nServiceFactory(cache, opts),
await userVerificationApiServiceFactory(cache, opts),
await userDecryptionOptionsServiceFactory(cache, opts),
await pinCryptoServiceFactory(cache, opts),
await logServiceFactory(cache, opts),
await vaultTimeoutSettingsServiceFactory(cache, opts),

View File

@ -65,7 +65,7 @@ export class AccountSwitcherService {
name: account.name ?? account.email,
email: account.email,
id: id,
server: await this.environmentService.getHost(id),
server: (await this.environmentService.getEnvironment(id))?.getHostname(),
status: account.status,
isActive: id === activeAccount?.id,
avatarColor: await firstValueFrom(

View File

@ -2,8 +2,8 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { HintComponent as BaseHintComponent } from "@bitwarden/angular/auth/components/hint.component";
import { LoginEmailServiceAbstraction } from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -20,9 +20,9 @@ export class HintComponent extends BaseHintComponent {
apiService: ApiService,
logService: LogService,
private route: ActivatedRoute,
loginService: LoginService,
loginEmailService: LoginEmailServiceAbstraction,
) {
super(router, i18nService, apiService, platformUtilsService, logService, loginService);
super(router, i18nService, apiService, platformUtilsService, logService, loginEmailService);
super.onSuccessfulSubmit = async () => {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.

View File

@ -30,7 +30,7 @@
</form>
<p class="createAccountLink">
{{ "newAroundHere" | i18n }}
<a routerLink="/register" (click)="setFormValues()">{{ "createAccount" | i18n }}</a>
<a routerLink="/register" (click)="setLoginEmailValues()">{{ "createAccount" | i18n }}</a>
</p>
</div>
</div>

View File

@ -1,14 +1,13 @@
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
import { Subject, firstValueFrom, takeUntil } from "rxjs";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
import { LoginEmailServiceAbstraction } from "@bitwarden/auth/common";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { AccountSwitcherService } from "./account-switching/services/account-switcher.service";
@ -29,38 +28,32 @@ export class HomeComponent implements OnInit, OnDestroy {
constructor(
protected platformUtilsService: PlatformUtilsService,
private stateService: StateService,
private formBuilder: FormBuilder,
private router: Router,
private i18nService: I18nService,
private environmentService: EnvironmentService,
private loginService: LoginService,
private loginEmailService: LoginEmailServiceAbstraction,
private accountSwitcherService: AccountSwitcherService,
) {}
async ngOnInit(): Promise<void> {
let savedEmail = this.loginService.getEmail();
const rememberEmail = this.loginService.getRememberEmail();
const email = this.loginEmailService.getEmail();
const rememberEmail = this.loginEmailService.getRememberEmail();
if (savedEmail != null) {
this.formGroup.patchValue({
email: savedEmail,
rememberEmail: rememberEmail,
});
if (email != null) {
this.formGroup.patchValue({ email, rememberEmail });
} else {
savedEmail = await this.stateService.getRememberedEmail();
if (savedEmail != null) {
this.formGroup.patchValue({
email: savedEmail,
rememberEmail: true,
});
const storedEmail = await firstValueFrom(this.loginEmailService.storedEmail$);
if (storedEmail != null) {
this.formGroup.patchValue({ email: storedEmail, rememberEmail: true });
}
}
this.environmentSelector.onOpenSelfHostedSettings
.pipe(takeUntil(this.destroyed$))
.subscribe(() => {
this.setFormValues();
this.setLoginEmailValues();
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.router.navigate(["environment"]);
@ -76,8 +69,9 @@ export class HomeComponent implements OnInit, OnDestroy {
return this.accountSwitcherService.availableAccounts$;
}
submit() {
async submit() {
this.formGroup.markAllAsTouched();
if (this.formGroup.invalid) {
this.platformUtilsService.showToast(
"error",
@ -87,19 +81,12 @@ export class HomeComponent implements OnInit, OnDestroy {
return;
}
this.loginService.setEmail(this.formGroup.value.email);
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
this.setLoginEmailValues();
await this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
}
get selfHostedDomain() {
return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null;
}
setFormValues() {
this.loginService.setEmail(this.formGroup.value.email);
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
setLoginEmailValues() {
this.loginEmailService.setEmail(this.formGroup.value.email);
this.loginEmailService.setRememberEmail(this.formGroup.value.rememberEmail);
}
}

View File

@ -9,6 +9,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaul
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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.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";
@ -62,6 +63,7 @@ export class LockComponent extends BaseLockComponent {
pinCryptoService: PinCryptoServiceAbstraction,
private routerService: BrowserRouterService,
biometricStateService: BiometricStateService,
accountService: AccountService,
) {
super(
router,
@ -84,6 +86,7 @@ export class LockComponent extends BaseLockComponent {
userVerificationService,
pinCryptoService,
biometricStateService,
accountService,
);
this.successRoute = "/tabs/current";
this.isInitialLockScreen = (window as any).previousPopupUrl == null;

View File

@ -1,17 +1,18 @@
import { Location } from "@angular/common";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { Component } from "@angular/core";
import { Router } from "@angular/router";
import { LoginViaAuthRequestComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-via-auth-request.component";
import {
AuthRequestServiceAbstraction,
LoginStrategyServiceAbstraction,
LoginEmailServiceAbstraction,
} from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service";
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";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
@ -28,10 +29,7 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv
selector: "app-login-via-auth-request",
templateUrl: "login-via-auth-request.component.html",
})
export class LoginViaAuthRequestComponent
extends BaseLoginWithDeviceComponent
implements OnInit, OnDestroy
{
export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent {
constructor(
router: Router,
cryptoService: CryptoService,
@ -47,11 +45,12 @@ export class LoginViaAuthRequestComponent
anonymousHubService: AnonymousHubService,
validationService: ValidationService,
stateService: StateService,
loginService: LoginService,
loginEmailService: LoginEmailServiceAbstraction,
syncService: SyncService,
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
authRequestService: AuthRequestServiceAbstraction,
loginStrategyService: LoginStrategyServiceAbstraction,
accountService: AccountService,
private location: Location,
) {
super(
@ -69,10 +68,11 @@ export class LoginViaAuthRequestComponent
anonymousHubService,
validationService,
stateService,
loginService,
loginEmailService,
deviceTrustCryptoService,
authRequestService,
loginStrategyService,
accountService,
);
super.onSuccessfulLogin = async () => {
await syncService.fullSync(true);

View File

@ -52,7 +52,7 @@
</div>
</div>
<div class="box-footer">
<button type="button" class="btn link" routerLink="/hint" (click)="setFormValues()">
<button type="button" class="btn link" routerLink="/hint" (click)="setLoginEmailValues()">
<b>{{ "getMasterPasswordHint" | i18n }}</b>
</button>
</div>

View File

@ -1,12 +1,15 @@
import { Component, NgZone } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
import {
LoginStrategyServiceAbstraction,
LoginEmailServiceAbstraction,
} from "@bitwarden/auth/common";
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
@ -45,7 +48,7 @@ export class LoginComponent extends BaseLoginComponent {
formBuilder: FormBuilder,
formValidationErrorService: FormValidationErrorsService,
route: ActivatedRoute,
loginService: LoginService,
loginEmailService: LoginEmailServiceAbstraction,
ssoLoginService: SsoLoginServiceAbstraction,
webAuthnLoginService: WebAuthnLoginServiceAbstraction,
) {
@ -65,7 +68,7 @@ export class LoginComponent extends BaseLoginComponent {
formBuilder,
formValidationErrorService,
route,
loginService,
loginEmailService,
ssoLoginService,
webAuthnLoginService,
);
@ -76,8 +79,8 @@ export class LoginComponent extends BaseLoginComponent {
this.showPasswordless = flagEnabled("showPasswordless");
if (this.showPasswordless) {
this.formGroup.controls.email.setValue(this.loginService.getEmail());
this.formGroup.controls.rememberEmail.setValue(this.loginService.getRememberEmail());
this.formGroup.controls.email.setValue(this.loginEmailService.getEmail());
this.formGroup.controls.rememberEmail.setValue(this.loginEmailService.getRememberEmail());
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.validateEmail();
@ -93,7 +96,7 @@ export class LoginComponent extends BaseLoginComponent {
async launchSsoBrowser() {
// Save off email for SSO
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
await this.loginService.saveEmailSettings();
await this.loginEmailService.saveEmailSettings();
// Generate necessary sso params
const passwordOptions: any = {
type: "password",
@ -114,7 +117,8 @@ export class LoginComponent extends BaseLoginComponent {
await this.ssoLoginService.setCodeVerifier(codeVerifier);
await this.ssoLoginService.setSsoState(state);
let url = this.environmentService.getWebVaultUrl();
const env = await firstValueFrom(this.environmentService.environment$);
let url = env.getWebVaultUrl();
if (url == null) {
url = "https://vault.bitwarden.com";
}

View File

@ -1,8 +1,5 @@
import { Injectable } from "@angular/core";
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards";
@Injectable()
export class UnauthGuardService extends BaseUnauthGuardService {
protected homepage = "tabs/current";
}

View File

@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
@ -37,6 +38,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
route: ActivatedRoute,
organizationApiService: OrganizationApiServiceAbstraction,
organizationUserService: OrganizationUserService,
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
ssoLoginService: SsoLoginServiceAbstraction,
dialogService: DialogService,
) {
@ -55,6 +57,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
stateService,
organizationApiService,
organizationUserService,
userDecryptionOptionsService,
ssoLoginService,
dialogService,
);

View File

@ -1,14 +1,18 @@
import { Component, Inject } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
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 { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
import {
LoginStrategyServiceAbstraction,
UserDecryptionOptionsServiceAbstraction,
} from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
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";
@ -39,7 +43,8 @@ export class SsoComponent extends BaseSsoComponent {
syncService: SyncService,
environmentService: EnvironmentService,
logService: LogService,
configService: ConfigServiceAbstraction,
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
configService: ConfigService,
protected authService: AuthService,
@Inject(WINDOW) private win: Window,
) {
@ -56,12 +61,13 @@ export class SsoComponent extends BaseSsoComponent {
environmentService,
passwordGenerationService,
logService,
userDecryptionOptionsService,
configService,
);
const url = this.environmentService.getWebVaultUrl();
this.redirectUri = url + "/sso-connector.html";
environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => {
this.redirectUri = env.getWebVaultUrl() + "/sso-connector.html";
});
this.clientId = "browser";
super.onSuccessfulLogin = async () => {

View File

@ -1,19 +1,22 @@
import { Component, Inject } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { Subject, Subscription } from "rxjs";
import { Subject, Subscription, firstValueFrom } from "rxjs";
import { filter, first, takeUntil } from "rxjs/operators";
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
import {
LoginStrategyServiceAbstraction,
LoginEmailServiceAbstraction,
UserDecryptionOptionsServiceAbstraction,
} from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { LoginService } from "@bitwarden/common/auth/abstractions/login.service";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
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 { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
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";
@ -54,8 +57,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
logService: LogService,
twoFactorService: TwoFactorService,
appIdService: AppIdService,
loginService: LoginService,
configService: ConfigServiceAbstraction,
loginEmailService: LoginEmailServiceAbstraction,
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
configService: ConfigService,
ssoLoginService: SsoLoginServiceAbstraction,
private dialogService: DialogService,
@Inject(WINDOW) protected win: Window,
@ -74,7 +78,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
logService,
twoFactorService,
appIdService,
loginService,
loginEmailService,
userDecryptionOptionsService,
ssoLoginService,
configService,
);
@ -220,7 +225,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
}
}
override launchDuoFrameless() {
override async launchDuoFrameless() {
const duoHandOffMessage = {
title: this.i18nService.t("youSuccessfullyLoggedIn"),
message: this.i18nService.t("youMayCloseThisWindow"),
@ -229,8 +234,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
// we're using the connector here as a way to set a cookie with translations
// before continuing to the duo frameless url
const env = await firstValueFrom(this.environmentService.environment$);
const launchUrl =
this.environmentService.getWebVaultUrl() +
env.getWebVaultUrl() +
"/duo-redirect-connector.html" +
"?duoFramelessUrl=" +
encodeURIComponent(this.duoFramelessUrl) +

View File

@ -113,7 +113,7 @@ type NotificationBackgroundExtensionMessageHandlers = {
bgGetEnableChangedPasswordPrompt: () => Promise<boolean>;
bgGetEnableAddedLoginPrompt: () => Promise<boolean>;
bgGetExcludedDomains: () => Promise<NeverDomains>;
getWebVaultUrlForNotification: () => string;
getWebVaultUrlForNotification: () => Promise<string>;
};
export {

View File

@ -1,13 +1,14 @@
import { mock } from "jest-mock-extended";
import { firstValueFrom } from "rxjs";
import { BehaviorSubject, firstValueFrom } from "rxjs";
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
@ -1348,16 +1349,21 @@ describe("NotificationBackground", () => {
const message: NotificationBackgroundExtensionMessage = {
command: "getWebVaultUrlForNotification",
};
const webVaultUrl = "https://example.com";
const env = new SelfHostedEnvironment({ webVault: "https://example.com" });
Object.defineProperty(environmentService, "environment$", {
configurable: true,
get: () => null,
});
const environmentServiceSpy = jest
.spyOn(environmentService, "getWebVaultUrl")
.mockReturnValueOnce(webVaultUrl);
.spyOn(environmentService as any, "environment$", "get")
.mockReturnValue(new BehaviorSubject(env).asObservable());
sendExtensionRuntimeMessage(message);
await flushPromises();
expect(environmentServiceSpy).toHaveBeenCalled();
expect(environmentServiceSpy).toHaveReturnedWith(webVaultUrl);
});
});
});

View File

@ -165,6 +165,7 @@ export default class NotificationBackground {
notificationQueueMessage: NotificationQueueMessageItem,
) {
const notificationType = notificationQueueMessage.type;
const typeData: Record<string, any> = {
isVaultLocked: notificationQueueMessage.wasVaultLocked,
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
@ -655,8 +656,9 @@ export default class NotificationBackground {
return await firstValueFrom(this.folderService.folderViews$);
}
private getWebVaultUrl(): string {
return this.environmentService.getWebVaultUrl();
private async getWebVaultUrl(): Promise<string> {
const env = await firstValueFrom(this.environmentService.environment$);
return env.getWebVaultUrl();
}
private async removeIndividualVault(): Promise<boolean> {

View File

@ -1,5 +1,5 @@
import { mock, mockReset } from "jest-mock-extended";
import { of } from "rxjs";
import { BehaviorSubject, of } from "rxjs";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
@ -12,9 +12,13 @@ import {
DefaultDomainSettingsService,
DomainSettingsService,
} from "@bitwarden/common/autofill/services/domain-settings.service";
import {
EnvironmentService,
Region,
} from "@bitwarden/common/platform/abstractions/environment.service";
import { ThemeType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
import { CloudEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
import { I18nService } from "@bitwarden/common/platform/services/i18n.service";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
import {
@ -48,8 +52,6 @@ import {
import OverlayBackground from "./overlay.background";
const iconServerUrl = "https://icons.bitwarden.com/";
describe("OverlayBackground", () => {
const mockUserId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
@ -61,9 +63,15 @@ describe("OverlayBackground", () => {
const cipherService = mock<CipherService>();
const autofillService = mock<AutofillService>();
const authService = mock<AuthService>();
const environmentService = mock<EnvironmentService>({
getIconsUrl: () => iconServerUrl,
});
const environmentService = mock<EnvironmentService>();
environmentService.environment$ = new BehaviorSubject(
new CloudEnvironment({
key: Region.US,
domain: "bitwarden.com",
urls: { icons: "https://icons.bitwarden.com/" },
}),
);
const stateService = mock<BrowserStateService>();
const autofillSettingsService = mock<AutofillSettingsService>();
const i18nService = mock<I18nService>();
@ -117,7 +125,8 @@ describe("OverlayBackground", () => {
describe("removePageDetails", () => {
it("removes the page details for a specific tab from the pageDetailsForTab object", () => {
const tabId = 1;
overlayBackground["pageDetailsForTab"][tabId] = [createPageDetailMock()];
const frameId = 2;
overlayBackground["pageDetailsForTab"][tabId] = new Map([[frameId, createPageDetailMock()]]);
overlayBackground.removePageDetails(tabId);
expect(overlayBackground["pageDetailsForTab"][tabId]).toBeUndefined();
@ -856,29 +865,40 @@ describe("OverlayBackground", () => {
sender,
);
expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual([
{ frameId: sender.frameId, tab: sender.tab, details: pageDetails1 },
]);
expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual(
new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }],
]),
);
});
it("updates the page details for a tab that already has a set of page details stored ", () => {
overlayBackground["pageDetailsForTab"][sender.tab.id] = [
{
frameId: sender.frameId,
tab: sender.tab,
details: pageDetails1,
},
];
const secondFrameSender = mock<chrome.runtime.MessageSender>({
tab: { id: 1 },
frameId: 3,
});
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }],
]);
sendExtensionRuntimeMessage(
{ command: "collectPageDetailsResponse", details: pageDetails2 },
sender,
secondFrameSender,
);
expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual([
{ frameId: sender.frameId, tab: sender.tab, details: pageDetails1 },
{ frameId: sender.frameId, tab: sender.tab, details: pageDetails2 },
]);
expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual(
new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }],
[
secondFrameSender.frameId,
{
frameId: secondFrameSender.frameId,
tab: secondFrameSender.tab,
details: pageDetails2,
},
],
]),
);
});
});
@ -1188,6 +1208,10 @@ describe("OverlayBackground", () => {
let getLoginCiphersSpy: jest.SpyInstance;
let isPasswordRepromptRequiredSpy: jest.SpyInstance;
let doAutoFillSpy: jest.SpyInstance;
let sender: chrome.runtime.MessageSender;
const pageDetails = createAutofillPageDetailsMock({
login: { username: "username1", password: "password1" },
});
beforeEach(() => {
getLoginCiphersSpy = jest.spyOn(overlayBackground["overlayLoginCiphers"], "get");
@ -1196,6 +1220,7 @@ describe("OverlayBackground", () => {
"isPasswordRepromptRequired",
);
doAutoFillSpy = jest.spyOn(overlayBackground["autofillService"], "doAutoFill");
sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
});
it("ignores the fill request if the overlay cipher id is not provided", async () => {
@ -1207,12 +1232,27 @@ describe("OverlayBackground", () => {
expect(doAutoFillSpy).not.toHaveBeenCalled();
});
it("ignores the fill request if the tab does not contain any identified page details", async () => {
sendPortMessage(listPortSpy, {
command: "fillSelectedListItem",
overlayCipherId: "overlay-cipher-1",
});
await flushPromises();
expect(getLoginCiphersSpy).not.toHaveBeenCalled();
expect(isPasswordRepromptRequiredSpy).not.toHaveBeenCalled();
expect(doAutoFillSpy).not.toHaveBeenCalled();
});
it("ignores the fill request if a master password reprompt is required", async () => {
const cipher = mock<CipherView>({
reprompt: CipherRepromptType.Password,
type: CipherType.Login,
});
overlayBackground["overlayLoginCiphers"] = new Map([["overlay-cipher-1", cipher]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }],
]);
getLoginCiphersSpy = jest.spyOn(overlayBackground["overlayLoginCiphers"], "get");
isPasswordRepromptRequiredSpy.mockResolvedValue(true);
@ -1239,6 +1279,14 @@ describe("OverlayBackground", () => {
["overlay-cipher-2", cipher2],
["overlay-cipher-3", cipher3],
]);
const pageDetailsForTab = {
frameId: sender.frameId,
tab: sender.tab,
details: pageDetails,
};
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, pageDetailsForTab],
]);
isPasswordRepromptRequiredSpy.mockResolvedValue(false);
sendPortMessage(listPortSpy, {
@ -1254,7 +1302,7 @@ describe("OverlayBackground", () => {
expect(doAutoFillSpy).toHaveBeenCalledWith({
tab: listPortSpy.sender.tab,
cipher: cipher2,
pageDetails: undefined,
pageDetails: [pageDetailsForTab],
fillNewPassword: true,
allowTotpAutofill: true,
});
@ -1270,6 +1318,9 @@ describe("OverlayBackground", () => {
it("copies the cipher's totp code to the clipboard after filling", async () => {
const cipher1 = mock<CipherView>({ id: "overlay-cipher-1" });
overlayBackground["overlayLoginCiphers"] = new Map([["overlay-cipher-1", cipher1]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }],
]);
isPasswordRepromptRequiredSpy.mockResolvedValue(false);
const copyToClipboardSpy = jest
.spyOn(overlayBackground["platformUtilsService"], "copyToClipboard")

View File

@ -47,13 +47,16 @@ class OverlayBackground implements OverlayBackgroundInterface {
private readonly openViewVaultItemPopout = openViewVaultItemPopout;
private readonly openAddEditVaultItemPopout = openAddEditVaultItemPopout;
private overlayLoginCiphers: Map<string, CipherView> = new Map();
private pageDetailsForTab: Record<number, PageDetail[]> = {};
private pageDetailsForTab: Record<
chrome.runtime.MessageSender["tab"]["id"],
Map<chrome.runtime.MessageSender["frameId"], PageDetail>
> = {};
private userAuthStatus: AuthenticationStatus = AuthenticationStatus.LoggedOut;
private overlayButtonPort: chrome.runtime.Port;
private overlayListPort: chrome.runtime.Port;
private focusedFieldData: FocusedFieldData;
private overlayPageTranslations: Record<string, string>;
private readonly iconsServerUrl: string;
private iconsServerUrl: string;
private readonly extensionMessageHandlers: OverlayBackgroundExtensionMessageHandlers = {
openAutofillOverlay: () => this.openOverlay(false),
autofillOverlayElementClosed: ({ message }) => this.overlayElementClosed(message),
@ -98,9 +101,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private themeStateService: ThemeStateService,
) {
this.iconsServerUrl = this.environmentService.getIconsUrl();
}
) {}
/**
* Removes cached page details for a tab
@ -109,6 +110,11 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param tabId - Used to reference the page details of a specific tab
*/
removePageDetails(tabId: number) {
if (!this.pageDetailsForTab[tabId]) {
return;
}
this.pageDetailsForTab[tabId].clear();
delete this.pageDetailsForTab[tabId];
}
@ -118,6 +124,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
*/
async init() {
this.setupExtensionMessageListeners();
const env = await firstValueFrom(this.environmentService.environment$);
this.iconsServerUrl = env.getIconsUrl();
await this.getOverlayVisibility();
await this.getAuthStatus();
}
@ -203,12 +211,13 @@ class OverlayBackground implements OverlayBackgroundInterface {
details: message.details,
};
if (this.pageDetailsForTab[sender.tab.id]?.length) {
this.pageDetailsForTab[sender.tab.id].push(pageDetails);
const pageDetailsMap = this.pageDetailsForTab[sender.tab.id];
if (!pageDetailsMap) {
this.pageDetailsForTab[sender.tab.id] = new Map([[sender.frameId, pageDetails]]);
return;
}
this.pageDetailsForTab[sender.tab.id] = [pageDetails];
pageDetailsMap.set(sender.frameId, pageDetails);
}
/**
@ -222,7 +231,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
{ overlayCipherId }: OverlayPortMessage,
{ sender }: chrome.runtime.Port,
) {
if (!overlayCipherId) {
const pageDetails = this.pageDetailsForTab[sender.tab.id];
if (!overlayCipherId || !pageDetails?.size) {
return;
}
@ -234,7 +244,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
const totpCode = await this.autofillService.doAutoFill({
tab: sender.tab,
cipher: cipher,
pageDetails: this.pageDetailsForTab[sender.tab.id],
pageDetails: Array.from(pageDetails.values()),
fillNewPassword: true,
allowTotpAutofill: true,
});

View File

@ -17,7 +17,7 @@ export default class WebRequestBackground {
private authService: AuthService,
) {
if (BrowserApi.isManifestVersion(2)) {
this.webRequest = (window as any).chrome.webRequest;
this.webRequest = chrome.webRequest;
}
this.isFirefox = platformUtilsService.isFirefox();
}

Some files were not shown because too many files have changed in this diff Show More