diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index 23f4bd35f1..f924c5c98e 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -164,6 +164,10 @@ jobs: run: npm run dist:mv3 working-directory: browser-source/apps/browser + - name: Build Chrome Manifest v3 Beta + run: npm run dist:chrome:beta + working-directory: browser-source/apps/browser + - name: Gulp run: gulp ci working-directory: browser-source/apps/browser @@ -196,6 +200,13 @@ jobs: path: browser-source/apps/browser/dist/dist-chrome-mv3.zip if-no-files-found: error + - name: Upload Chrome MV3 Beta artifact (DO NOT USE FOR PROD) + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: DO-NOT-USE-FOR-PROD-dist-chrome-MV3-beta-${{ env._BUILD_NUMBER }}.zip + path: browser-source/apps/browser/dist/dist-chrome-mv3-beta.zip + if-no-files-found: error + - name: Upload Firefox artifact uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index 6a5d9f1405..b034136f58 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -230,6 +230,17 @@ jobs: url: https://github.com/bitwarden/clients/actions/runs/${{ github.run_id }} AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + update-summary: + name: Display commit + needs: artifact-check + runs-on: ubuntu-22.04 + steps: + - name: Display commit SHA + run: | + REPO_URL="https://github.com/bitwarden/clients/commit" + COMMIT_SHA="${{ needs.artifact-check.outputs.artifact-build-commit }}" + echo ":steam_locomotive: View [commit]($REPO_URL/$COMMIT_SHA)" >> $GITHUB_STEP_SUMMARY + azure-deploy: name: Deploy Web Vault to ${{ inputs.environment }} Storage Account needs: diff --git a/.github/workflows/release-desktop-beta.yml b/.github/workflows/release-desktop-beta.yml index b9e2d7a8c8..46f4ffad57 100644 --- a/.github/workflows/release-desktop-beta.yml +++ b/.github/workflows/release-desktop-beta.yml @@ -955,11 +955,7 @@ jobs: keyvault: "bitwarden-ci" secrets: "aws-electron-access-id, aws-electron-access-key, - aws-electron-bucket-name, - r2-electron-access-id, - r2-electron-access-key, - r2-electron-bucket-name, - cf-prod-account" + aws-electron-bucket-name" - name: Download all artifacts uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 @@ -985,20 +981,6 @@ jobs: --recursive \ --quiet - - name: Publish artifacts to R2 - env: - AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }} - AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }} - AWS_DEFAULT_REGION: 'us-east-1' - AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }} - CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }} - working-directory: apps/desktop/artifacts - run: | - aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \ - --recursive \ - --quiet \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com - - name: Update deployment status to Success if: ${{ success() }} uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index cf857d7177..dc6957d00d 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -115,11 +115,7 @@ jobs: keyvault: "bitwarden-ci" secrets: "aws-electron-access-id, aws-electron-access-key, - aws-electron-bucket-name, - r2-electron-access-id, - r2-electron-access-key, - r2-electron-bucket-name, - cf-prod-account" + aws-electron-bucket-name" - name: Download all artifacts if: ${{ github.event.inputs.release_type != 'Dry Run' }} @@ -169,21 +165,6 @@ jobs: --recursive \ --quiet - - name: Publish artifacts to R2 - if: ${{ github.event.inputs.release_type != 'Dry Run' && github.event.inputs.electron_publish == 'true' }} - env: - AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }} - AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }} - AWS_DEFAULT_REGION: 'us-east-1' - AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }} - CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }} - working-directory: apps/desktop/artifacts - run: | - aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \ - --recursive \ - --quiet \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com - - name: Get checksum files uses: bitwarden/gh-actions/get-checksum@main with: diff --git a/.github/workflows/staged-rollout-desktop.yml b/.github/workflows/staged-rollout-desktop.yml index a5b5fc69b1..a6ca2f1e31 100644 --- a/.github/workflows/staged-rollout-desktop.yml +++ b/.github/workflows/staged-rollout-desktop.yml @@ -31,29 +31,21 @@ jobs: keyvault: "bitwarden-ci" secrets: "aws-electron-access-id, aws-electron-access-key, - aws-electron-bucket-name, - r2-electron-access-id, - r2-electron-access-key, - r2-electron-bucket-name, - cf-prod-account" + aws-electron-bucket-name" - - name: Download channel update info files from R2 + - name: Download channel update info files from S3 env: - AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }} - AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }} - AWS_DEFAULT_REGION: 'us-east-1' - AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }} - CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }} + AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }} + AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }} + AWS_DEFAULT_REGION: 'us-west-2' + AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }} run: | aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest.yml . \ --quiet \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-linux.yml . \ --quiet \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-mac.yml . \ --quiet \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com - name: Check new rollout percentage env: @@ -95,20 +87,3 @@ jobs: aws s3 cp latest-mac.yml $AWS_S3_BUCKET_NAME/desktop/ \ --acl "public-read" - - - name: Publish channel update info files to R2 - env: - AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.r2-electron-access-id }} - AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.r2-electron-access-key }} - AWS_DEFAULT_REGION: 'us-east-1' - AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.r2-electron-bucket-name }} - CF_ACCOUNT: ${{ steps.retrieve-secrets.outputs.cf-prod-account }} - run: | - aws s3 cp latest.yml $AWS_S3_BUCKET_NAME/desktop/ \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com - - aws s3 cp latest-linux.yml $AWS_S3_BUCKET_NAME/desktop/ \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com - - aws s3 cp latest-mac.yml $AWS_S3_BUCKET_NAME/desktop/ \ - --endpoint-url https://${CF_ACCOUNT}.r2.cloudflarestorage.com diff --git a/.storybook/main.ts b/.storybook/main.ts index c71a74c2a7..cb63ada550 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -9,6 +9,8 @@ const config: StorybookConfig = { "../libs/components/src/**/*.stories.@(js|jsx|ts|tsx)", "../apps/web/src/**/*.mdx", "../apps/web/src/**/*.stories.@(js|jsx|ts|tsx)", + "../apps/browser/src/**/*.mdx", + "../apps/browser/src/**/*.stories.@(js|jsx|ts|tsx)", "../bitwarden_license/bit-web/src/**/*.mdx", "../bitwarden_license/bit-web/src/**/*.stories.@(js|jsx|ts|tsx)", ], diff --git a/.storybook/tsconfig.json b/.storybook/tsconfig.json index 113cc5bcde..34acc9a740 100644 --- a/.storybook/tsconfig.json +++ b/.storybook/tsconfig.json @@ -1,12 +1,10 @@ { "extends": "../tsconfig", "compilerOptions": { - "types": ["node", "jest", "chrome"], "allowSyntheticDefaultImports": true }, - "exclude": ["../src/test.setup.ts", "../apps/src/**/*.spec.ts", "../libs/**/*.spec.ts"], + "exclude": ["../src/test.setup.ts", "../apps/**/*.spec.ts", "../libs/**/*.spec.ts"], "files": [ - "./typings.d.ts", "./preview.tsx", "../libs/components/src/main.ts", "../libs/components/src/polyfills.ts" diff --git a/.storybook/typings.d.ts b/.storybook/typings.d.ts deleted file mode 100644 index c94d67b1a2..0000000000 --- a/.storybook/typings.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.md" { - const content: string; - export default content; -} diff --git a/apps/browser/gulpfile.js b/apps/browser/gulpfile.js index 6a0980fc27..d5b29ffc38 100644 --- a/apps/browser/gulpfile.js +++ b/apps/browser/gulpfile.js @@ -35,6 +35,9 @@ function buildString() { if (process.env.MANIFEST_VERSION) { build = `-mv${process.env.MANIFEST_VERSION}`; } + if (process.env.BETA_BUILD === "1") { + build += "-beta"; + } if (process.env.BUILD_NUMBER && process.env.BUILD_NUMBER !== "") { build = `-${process.env.BUILD_NUMBER}`; } @@ -65,6 +68,9 @@ function distFirefox() { manifest.optional_permissions = manifest.optional_permissions.filter( (permission) => permission !== "privacy", ); + if (process.env.BETA_BUILD === "1") { + manifest = applyBetaLabels(manifest); + } return manifest; }); } @@ -72,6 +78,9 @@ function distFirefox() { function distOpera() { return dist("opera", (manifest) => { delete manifest.applications; + if (process.env.BETA_BUILD === "1") { + manifest = applyBetaLabels(manifest); + } return manifest; }); } @@ -81,6 +90,9 @@ function distChrome() { delete manifest.applications; delete manifest.sidebar_action; delete manifest.commands._execute_sidebar_action; + if (process.env.BETA_BUILD === "1") { + manifest = applyBetaLabels(manifest); + } return manifest; }); } @@ -90,6 +102,9 @@ function distEdge() { delete manifest.applications; delete manifest.sidebar_action; delete manifest.commands._execute_sidebar_action; + if (process.env.BETA_BUILD === "1") { + manifest = applyBetaLabels(manifest); + } return manifest; }); } @@ -210,6 +225,9 @@ async function safariCopyBuild(source, dest) { delete manifest.commands._execute_sidebar_action; delete manifest.optional_permissions; manifest.permissions.push("nativeMessaging"); + if (process.env.BETA_BUILD === "1") { + manifest = applyBetaLabels(manifest); + } return manifest; }), ), @@ -235,6 +253,19 @@ async function ciCoverage(cb) { .pipe(gulp.dest(paths.coverage)); } +function applyBetaLabels(manifest) { + manifest.name = "Bitwarden Password Manager BETA"; + manifest.short_name = "Bitwarden BETA"; + manifest.description = "THIS EXTENSION IS FOR BETA TESTING BITWARDEN."; + if (process.env.GITHUB_RUN_ID) { + manifest.version_name = `${manifest.version} beta - ${process.env.GITHUB_SHA.slice(0, 8)}`; + manifest.version = `${manifest.version}.${parseInt(process.env.GITHUB_RUN_ID.slice(-4))}`; + } else { + manifest.version = `${manifest.version}.0`; + } + return manifest; +} + exports["dist:firefox"] = distFirefox; exports["dist:chrome"] = distChrome; exports["dist:opera"] = distOpera; diff --git a/apps/browser/package.json b/apps/browser/package.json index 506f19f279..580acfc3d0 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -7,10 +7,14 @@ "build:watch": "webpack --watch", "build:watch:mv3": "cross-env MANIFEST_VERSION=3 webpack --watch", "build:prod": "cross-env NODE_ENV=production webpack", + "build:prod:beta": "cross-env BETA_BUILD=1 NODE_ENV=production webpack", "build:prod:watch": "cross-env NODE_ENV=production webpack --watch", "dist": "npm run build:prod && gulp dist", + "dist:beta": "npm run build:prod:beta && cross-env BETA_BUILD=1 gulp dist", "dist:mv3": "cross-env MANIFEST_VERSION=3 npm run build:prod && cross-env MANIFEST_VERSION=3 gulp dist", + "dist:mv3:beta": "cross-env MANIFEST_VERSION=3 npm run build:prod:beta && cross-env MANIFEST_VERSION=3 BETA_BUILD=1 gulp dist", "dist:chrome": "npm run build:prod && gulp dist:chrome", + "dist:chrome:beta": "cross-env MANIFEST_VERSION=3 npm run build:prod:beta && cross-env MANIFEST_VERSION=3 BETA_BUILD=1 gulp dist:chrome", "dist:firefox": "npm run build:prod && gulp dist:firefox", "dist:opera": "npm run build:prod && gulp dist:opera", "dist:safari": "npm run build:prod && gulp dist:safari", diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index e08894be0b..996142b5ad 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "قم بالتسجيل أو إنشاء حساب جديد للوصول إلى خزنتك الآمنة." diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 1e5062d8c6..a58ada8eb1 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Güvənli anbarınıza müraciət etmək üçün giriş edin və ya yeni bir hesab yaradın." diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 91ff397b3a..82fd4fa5d4 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Увайдзіце або стварыце новы ўліковы запіс для доступу да бяспечнага сховішча." diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 33be2608b4..b6d41cb622 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Впишете се или създайте нов абонамент, за да достъпите защитен трезор." diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index a12308648a..dec1bc6cfa 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "আপনার সুরক্ষিত ভল্টে প্রবেশ করতে লগ ইন করুন অথবা একটি নতুন অ্যাকাউন্ট তৈরি করুন।" diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 7f406fabee..9d3113e3f6 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Prijavite se ili napravite novi račun da biste pristupili svom sigurnom trezoru." diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 7c8bd63aea..8063ba79d8 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Inicieu sessió o creeu un compte nou per accedir a la caixa forta." diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index bd3c6882df..ee58f3d263 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Pro přístup do Vašeho bezpečného trezoru se přihlaste nebo si vytvořte nový účet." diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index c718c1d876..a80dca5f92 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Mewngofnodwch neu crëwch gyfrif newydd i gael mynediad i'ch cell ddiogel." @@ -23,7 +23,7 @@ "message": "Enterprise single sign-on" }, "cancel": { - "message": "Cancel" + "message": "Canslo" }, "close": { "message": "Cau" @@ -318,7 +318,7 @@ "message": "Golygu" }, "view": { - "message": "View" + "message": "Gweld" }, "noItemsInList": { "message": "Does dim eitemau i'w rhestru." @@ -549,10 +549,10 @@ "message": "Ydych chi'n siŵr eich bod am allgofnodi?" }, "yes": { - "message": "Yes" + "message": "Ydw" }, "no": { - "message": "No" + "message": "Na" }, "unexpectedError": { "message": "An unexpected error has occurred." diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 777c3b484f..215d79eb21 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log ind eller opret en ny konto for at få adgang til din sikre boks." diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 8f2a59af1e..fbc193dbae 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -3,12 +3,12 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden Passwortmanager", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Melde dich an oder erstelle ein neues Konto, um auf deinen Tresor zuzugreifen." @@ -173,10 +173,10 @@ "message": "Master-Passwort ändern" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Weiter zur Web-App?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Du kannst dein Master-Passwort in der Bitwarden Web-App ändern." }, "fingerprintPhrase": { "message": "Fingerabdruck-Phrase", @@ -3001,7 +3001,7 @@ "description": "Notification message for when saving credentials has failed." }, "success": { - "message": "Success" + "message": "Erfolg" }, "removePasskey": { "message": "Passkey entfernen" @@ -3010,21 +3010,21 @@ "message": "Passkey entfernt" }, "unassignedItemsBannerNotice": { - "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." + "message": "Hinweis: Nicht zugeordnete Organisationseinträge sind nicht mehr in der Ansicht aller Tresore sichtbar und nur über die Administrator-Konsole zugänglich." }, "unassignedItemsBannerSelfHostNotice": { - "message": "Notice: On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and will only be accessible via the Admin Console." + "message": "Hinweis: Ab dem 16. Mai 2024 sind nicht zugewiesene Organisationselemente nicht mehr in der Ansicht aller Tresore sichtbar und nur über die Administrator-Konsole zugänglich." }, "unassignedItemsBannerCTAPartOne": { - "message": "Assign these items to a collection from the", + "message": "Weise diese Einträge einer Sammlung aus der", "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "unassignedItemsBannerCTAPartTwo": { - "message": "to make them visible.", + "message": "zu, um sie sichtbar zu machen.", "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "adminConsole": { - "message": "Admin Console" + "message": "Administrator-Konsole" }, "errorAssigningTargetCollection": { "message": "Fehler beim Zuweisen der Ziel-Sammlung." diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 8c65e61e53..5c85aeff58 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Συνδεθείτε ή δημιουργήστε ένα νέο λογαριασμό για να αποκτήσετε πρόσβαση στο ασφαλές vault σας." diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 7e6e333689..1c0b178895 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index e4d90adf1a..087cd3faa8 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 7cc17240d2..f370af7f36 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 3e488bce4c..9e89f453df 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Identifícate o crea una nueva cuenta para acceder a tu caja fuerte." diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 785a3e4986..5705a5a0d2 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Logi oma olemasolevasse kontosse sisse või loo uus konto." diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 9a07b9d9ae..ee3b5f1329 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Saioa hasi edo sortu kontu berri bat zure kutxa gotorrera sartzeko." diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index c68dc43ef4..e2f0e96c86 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "وارد شوید یا یک حساب کاربری بسازید تا به گاوصندوق امن‌تان دسترسی یابید." diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 2cdb6a2379..746f4f45be 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Kotona, töissä tai reissussa, Bitwarden suojaa helposti kaikki salasanasi, avainkoodisi ja arkaluonteiset tietosi.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Käytä salattua holviasi kirjautumalla sisään tai luo uusi tili." diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 0dfb4a39c9..abb999d032 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Maglog-in o gumawa ng bagong account para ma-access ang iyong ligtas na kahadeyero." diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 742e31ee58..de35f71832 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Identifiez-vous ou créez un nouveau compte pour accéder à votre coffre sécurisé." diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index b4c151eeb0..3dd737f0a8 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 61482da54a..5d343ae807 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "צור חשבון חדש או התחבר כדי לגשת לכספת המאובטחת שלך." diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index b76405eed8..fa4051d3e9 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "अपनी सुरक्षित तिजोरी में प्रवेश करने के लिए नया खाता बनाएं या लॉग इन करें।" diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index 2dc500bc1e..c9b8741509 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Prijavi se ili stvori novi račun za pristup svojem sigurnom trezoru." diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index e47f2cda1f..5d5b174435 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Bejelentkezés vagy új fiók létrehozása a biztonsági széf eléréséhez." diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index d4399d8e15..b54e854d27 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Masuk atau buat akun baru untuk mengakses brankas Anda." diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 93ae682190..91d10253a0 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Accedi o crea un nuovo account per accedere alla tua cassaforte." diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 52ff21727a..967dc222e5 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "安全なデータ保管庫へアクセスするためにログインまたはアカウントを作成してください。" diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 2c18502eca..c73c366195 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 5d1b024c60..b6384bb840 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index 047270808e..178cd7c45f 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "ನಿಮ್ಮ ಸುರಕ್ಷಿತ ವಾಲ್ಟ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಲಾಗ್ ಇನ್ ಮಾಡಿ ಅಥವಾ ಹೊಸ ಖಾತೆಯನ್ನು ರಚಿಸಿ." diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 4bc4302f8b..95a7727b83 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -3,12 +3,12 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden 비밀번호 관리자", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "집에서도, 직장에서도, 이동 중에도 Bitwarden은 비밀번호, 패스키, 민감 정보를 쉽게 보호합니다.", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "안전 보관함에 접근하려면 로그인하거나 새 계정을 만드세요." @@ -173,7 +173,7 @@ "message": "마스터 비밀번호 변경" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "웹 앱에서 계속하시겠용?" }, "changeMasterPasswordOnWebConfirmation": { "message": "You can change your master password on the Bitwarden web app." @@ -688,10 +688,10 @@ "message": "Ask to update a login's password when a change is detected on a website. Applies to all logged in accounts." }, "enableUsePasskeys": { - "message": "Ask to save and use passkeys" + "message": "패스키를 저장 및 사용할지 묻기" }, "usePasskeysDesc": { - "message": "Ask to save new passkeys or log in with passkeys stored in your vault. Applies to all logged in accounts." + "message": "보관함에 새 패스키를 저장하거나 로그인할지 물어봅니다. 모든 로그인된 계정에 적용됩니다." }, "notificationChangeDesc": { "message": "Bitwarden에 저장되어 있는 비밀번호를 이 비밀번호로 변경하시겠습니까?" @@ -2786,55 +2786,55 @@ "message": "Confirm file password" }, "typePasskey": { - "message": "Passkey" + "message": "패스키" }, "passkeyNotCopied": { - "message": "Passkey will not be copied" + "message": "패스키가 복사되지 않습니다" }, "passkeyNotCopiedAlert": { - "message": "The passkey will not be copied to the cloned item. Do you want to continue cloning this item?" + "message": "패스키는 복제된 아이템에 복사되지 않습니다. 계속 이 항목을 복제하시겠어요?" }, "passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": { - "message": "Verification required by the initiating site. This feature is not yet implemented for accounts without master password." + "message": "사이트에서 인증을 요구합니다. 이 기능은 비밀번호가 없는 계정에서는 아직 지원하지 않습니다." }, "logInWithPasskey": { - "message": "Log in with passkey?" + "message": "패스키로 로그인하시겠어요?" }, "passkeyAlreadyExists": { - "message": "A passkey already exists for this application." + "message": "이미 이 애플리케이션에 해당하는 패스키가 있습니다." }, "noPasskeysFoundForThisApplication": { - "message": "No passkeys found for this application." + "message": "이 애플리케이션에 대한 패스키를 찾을 수 없습니다." }, "noMatchingPasskeyLogin": { - "message": "You do not have a matching login for this site." + "message": "사이트와 일치하는 로그인이 없습니다." }, "confirm": { "message": "Confirm" }, "savePasskey": { - "message": "Save passkey" + "message": "패스키 저장" }, "savePasskeyNewLogin": { - "message": "Save passkey as new login" + "message": "새 로그인으로 패스키 저장" }, "choosePasskey": { - "message": "Choose a login to save this passkey to" + "message": "패스키를 저장할 로그인 선택하기" }, "passkeyItem": { - "message": "Passkey Item" + "message": "패스키 항목" }, "overwritePasskey": { - "message": "Overwrite passkey?" + "message": "비밀번호를 덮어쓰시겠어요?" }, "overwritePasskeyAlert": { - "message": "This item already contains a passkey. Are you sure you want to overwrite the current passkey?" + "message": "이 항목은 이미 패스키가 있습니다. 정말로 현재 패스키를 덮어쓰시겠어요?" }, "featureNotSupported": { "message": "Feature not yet supported" }, "yourPasskeyIsLocked": { - "message": "Authentication required to use passkey. Verify your identity to continue." + "message": "패스키를 사용하려면 인증이 필요합니다. 인증을 진행해주세요." }, "multifactorAuthenticationCancelled": { "message": "Multifactor authentication cancelled" @@ -3004,10 +3004,10 @@ "message": "Success" }, "removePasskey": { - "message": "Remove passkey" + "message": "패스키 제거" }, "passkeyRemoved": { - "message": "Passkey removed" + "message": "패스키 제거됨" }, "unassignedItemsBannerNotice": { "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index b1a2c857e0..a01c5069e8 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Prisijunkite arba sukurkite naują paskyrą, kad galėtumėte pasiekti saugyklą." diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 4055693486..f24f0a93fc 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Jāpiesakās vai jāizveido jauns konts, lai piekļūtu drošajai glabātavai." diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index d9703137fe..334027b407 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "നിങ്ങളുടെ സുരക്ഷിത വാൾട്ടിലേക്കു പ്രവേശിക്കാൻ ലോഗിൻ ചെയ്യുക അല്ലെങ്കിൽ ഒരു പുതിയ അക്കൗണ്ട് സൃഷ്ടിക്കുക." diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index f67f617d3b..b0e9f8abc1 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "तुमच्या सुरक्षित तिजोरीत पोहचण्यासाठी लॉग इन करा किंवा नवीन खाते उघडा." diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index 5d1b024c60..b6384bb840 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 649163a8dc..163154b2f2 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Logg på eller opprett en ny konto for å få tilgang til ditt sikre hvelv." diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index 5d1b024c60..b6384bb840 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 5a52b4f7ef..cd76fc9684 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in of maak een nieuw account aan om toegang te krijgen tot je beveiligde kluis." @@ -531,7 +531,7 @@ "message": "Kan de QR-code van de huidige webpagina niet scannen" }, "totpCaptureSuccess": { - "message": "Authenticatie-sleutel toegevoegd" + "message": "Authenticatiesleutel toegevoegd" }, "totpCapture": { "message": "Scan de authenticatie-QR-code van de huidige webpagina" @@ -1673,10 +1673,10 @@ "message": "Browserintegratie is niet ingeschakeld in de Bitwarden-desktopapplicatie. Schakel deze optie in de instellingen binnen de desktop-applicatie in." }, "startDesktopTitle": { - "message": "Bitwarden-desktopapplicatie opstarten" + "message": "Bitwarden desktopapplicatie opstarten" }, "startDesktopDesc": { - "message": "Je moet de Bitwarden-desktopapplicatie starten om deze functie te gebruiken." + "message": "Je moet de Bitwarden desktopapplicatie starten om deze functie te gebruiken." }, "errorEnableBiometricTitle": { "message": "Kon biometrie niet inschakelen" diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 5d1b024c60..b6384bb840 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index 5d1b024c60..b6384bb840 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index e768a70d52..1a56d32a35 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -3,12 +3,12 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Menedżer Haseł Bitwarden", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "W domu, w pracy, lub w ruchu, Bitwarden z łatwością zabezpiecza Twoje hasła, passkeys i poufne informacje", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Zaloguj się lub utwórz nowe konto, aby uzyskać dostęp do Twojego bezpiecznego sejfu." diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index c6e62fbd4f..0f40bc63bb 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -3,12 +3,12 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden Gerenciador de Senhas", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "Em qual lugar for, o Bitwarden protege suas senhas, chaves de acesso, e informações confidenciais", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Inicie a sessão ou crie uma nova conta para acessar seu cofre seguro." @@ -173,10 +173,10 @@ "message": "Alterar Senha Mestra" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Continuar no aplicativo web?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Você pode alterar a sua senha mestra no aplicativo web Bitwarden." }, "fingerprintPhrase": { "message": "Frase Biométrica", @@ -500,10 +500,10 @@ "message": "A sua nova conta foi criada! Agora você pode iniciar a sessão." }, "youSuccessfullyLoggedIn": { - "message": "You successfully logged in" + "message": "Você logou na sua conta com sucesso" }, "youMayCloseThisWindow": { - "message": "You may close this window" + "message": "Você pode fechar esta janela" }, "masterPassSent": { "message": "Enviamos um e-mail com a dica da sua senha mestra." @@ -1500,7 +1500,7 @@ "message": "Código PIN inválido." }, "tooManyInvalidPinEntryAttemptsLoggingOut": { - "message": "Too many invalid PIN entry attempts. Logging out." + "message": "Muitas tentativas de entrada de PIN inválidas. Desconectando." }, "unlockWithBiometrics": { "message": "Desbloquear com a biometria" @@ -2005,7 +2005,7 @@ "message": "Selecionar pasta..." }, "noFoldersFound": { - "message": "No folders found", + "message": "Nenhuma pasta encontrada", "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": "Verificação necessária", "description": "Default title for the user verification dialog." }, "hours": { @@ -2652,40 +2652,40 @@ } }, "tryAgain": { - "message": "Try again" + "message": "Tentar novamente" }, "verificationRequiredForActionSetPinToContinue": { - "message": "Verification required for this action. Set a PIN to continue." + "message": "Verificação necessária para esta ação. Defina um PIN para continuar." }, "setPin": { - "message": "Set PIN" + "message": "Definir PIN" }, "verifyWithBiometrics": { - "message": "Verify with biometrics" + "message": "Verificiar com biometria" }, "awaitingConfirmation": { - "message": "Awaiting confirmation" + "message": "Aguardando confirmação" }, "couldNotCompleteBiometrics": { - "message": "Could not complete biometrics." + "message": "Não foi possível completar a biometria." }, "needADifferentMethod": { - "message": "Need a different method?" + "message": "Precisa de um método diferente?" }, "useMasterPassword": { - "message": "Use master password" + "message": "Usar a senha mestra" }, "usePin": { - "message": "Use PIN" + "message": "Usar PIN" }, "useBiometrics": { - "message": "Use biometrics" + "message": "Usar biometria" }, "enterVerificationCodeSentToEmail": { - "message": "Enter the verification code that was sent to your email." + "message": "Digite o código de verificação que foi enviado para o seu e-mail." }, "resendCode": { - "message": "Resend code" + "message": "Reenviar código" }, "total": { "message": "Total" @@ -2700,19 +2700,19 @@ } }, "launchDuoAndFollowStepsToFinishLoggingIn": { - "message": "Launch Duo and follow the steps to finish logging in." + "message": "Inicie o Duo e siga os passos para finalizar o login." }, "duoRequiredForAccount": { - "message": "Duo two-step login is required for your account." + "message": "A autenticação em duas etapas do Duo é necessária para sua conta." }, "popoutTheExtensionToCompleteLogin": { - "message": "Popout the extension to complete login." + "message": "Abra a extensão para concluir o login." }, "popoutExtension": { - "message": "Popout extension" + "message": "Extensão pop-out" }, "launchDuo": { - "message": "Launch Duo" + "message": "Abrir o Duo" }, "importFormatError": { "message": "Os dados não estão formatados corretamente. Por favor, verifique o seu arquivo de importação e tente novamente." @@ -2846,13 +2846,13 @@ "message": "Nome de usuário ou senha incorretos" }, "incorrectPassword": { - "message": "Incorrect password" + "message": "Senha incorreta" }, "incorrectCode": { - "message": "Incorrect code" + "message": "Código incorreto" }, "incorrectPin": { - "message": "Incorrect PIN" + "message": "PIN incorreto" }, "multifactorAuthenticationFailed": { "message": "Falha na autenticação de múltiplos fatores" @@ -2965,71 +2965,71 @@ "description": "Label indicating the most common import formats" }, "overrideDefaultBrowserAutofillTitle": { - "message": "Make Bitwarden your default password manager?", + "message": "Tornar o Bitwarden seu gerenciador de senhas padrão?", "description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior" }, "overrideDefaultBrowserAutofillDescription": { - "message": "Ignoring this option may cause conflicts between the Bitwarden auto-fill menu and your browser's.", + "message": "Ignorar esta opção pode causar conflitos entre o menu de autopreenchimento do Bitwarden e o do seu navegador.", "description": "Dialog message facilitating the ability to override a chrome browser's default autofill behavior" }, "overrideDefaultBrowserAutoFillSettings": { - "message": "Make Bitwarden your default password manager", + "message": "Faça do Bitwarden seu gerenciador de senhas padrão", "description": "Label for the setting that allows overriding the default browser autofill settings" }, "privacyPermissionAdditionNotGrantedTitle": { - "message": "Unable to set Bitwarden as the default password manager", + "message": "Não é possível definir o Bitwarden como o gerenciador de senhas padrão", "description": "Title for the dialog that appears when the user has not granted the extension permission to set privacy settings" }, "privacyPermissionAdditionNotGrantedDescription": { - "message": "You must grant browser privacy permissions to Bitwarden to set it as the default password manager.", + "message": "Você deve conceder permissões de privacidade do navegador ao Bitwarden para defini-lo como o Gerenciador de Senhas padrão.", "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": "Tornar padrão", "description": "Button text for the setting that allows overriding the default browser autofill settings" }, "saveCipherAttemptSuccess": { - "message": "Credentials saved successfully!", + "message": "Credenciais salvas com sucesso!", "description": "Notification message for when saving credentials has succeeded." }, "updateCipherAttemptSuccess": { - "message": "Credentials updated successfully!", + "message": "Credenciais atualizadas com sucesso!", "description": "Notification message for when updating credentials has succeeded." }, "saveCipherAttemptFailed": { - "message": "Error saving credentials. Check console for details.", + "message": "Erro ao salvar credenciais. Verifique o console para detalhes.", "description": "Notification message for when saving credentials has failed." }, "success": { - "message": "Success" + "message": "Sucesso" }, "removePasskey": { - "message": "Remove passkey" + "message": "Remover senha" }, "passkeyRemoved": { - "message": "Passkey removed" + "message": "Chave de acesso removida" }, "unassignedItemsBannerNotice": { - "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." + "message": "Aviso: Itens da organização não atribuídos não estão mais visíveis na visualização Todos os Cofres e só são acessíveis por meio do painel de administração." }, "unassignedItemsBannerSelfHostNotice": { - "message": "Notice: On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and will only be accessible via the Admin Console." + "message": "Aviso: Em 16 de maio, 2024, itens da organização não serão mais visíveis na visualização Todos os Cofres e só serão acessíveis por meio do painel de administração." }, "unassignedItemsBannerCTAPartOne": { - "message": "Assign these items to a collection from the", + "message": "Atribua estes itens a uma coleção da", "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "unassignedItemsBannerCTAPartTwo": { - "message": "to make them visible.", + "message": "para torná-los visíveis.", "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "adminConsole": { - "message": "Admin Console" + "message": "Painel de administração" }, "errorAssigningTargetCollection": { - "message": "Error assigning target collection." + "message": "Erro ao atribuir coleção de destino." }, "errorAssigningTargetFolder": { - "message": "Error assigning target folder." + "message": "Erro ao atribuir pasta de destino." } } diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 06ba8eed26..6d6fd70276 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Inicie sessão ou crie uma nova conta para aceder ao seu cofre seguro." diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index b3e0a2066f..780bf69b93 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Autentificați-vă sau creați un cont nou pentru a accesa seiful dvs. securizat." diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index e594dbdce2..927095a3f6 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Войдите или создайте новый аккаунт для доступа к вашему защищенному хранилищу." diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index 05e2dc3edd..33b03f574b 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "ඔබගේ ආරක්ෂිත සුරක්ෂිතාගාරය වෙත පිවිසීමට හෝ නව ගිණුමක් නිර්මාණය කරන්න." diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index eab1d105eb..c84cfbb778 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Prihláste sa, alebo vytvorte nový účet pre prístup k vášmu bezpečnému trezoru." diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 935678efc8..4a6b7cd214 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Prijavite se ali ustvarite nov račun za dostop do svojega varnega trezorja." diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 5819546800..a04a7ecd70 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Пријавите се или креирајте нови налог за приступ сефу." @@ -173,10 +173,10 @@ "message": "Промени главну лозинку" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Ићи на веб апликацију?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Можете променити главну лозинку на Bitwarden веб апликацији." }, "fingerprintPhrase": { "message": "Сигурносна Фраза Сефа", @@ -3001,7 +3001,7 @@ "description": "Notification message for when saving credentials has failed." }, "success": { - "message": "Success" + "message": "Успех" }, "removePasskey": { "message": "Уклонити приступачни кључ" @@ -3010,10 +3010,10 @@ "message": "Приступачни кључ је уклоњен" }, "unassignedItemsBannerNotice": { - "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." + "message": "Напомена: Недодељене ставке организације више нису видљиве у приказу Сви сефови и доступне су само преко Админ конзоле." }, "unassignedItemsBannerSelfHostNotice": { - "message": "Notice: On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and will only be accessible via the Admin Console." + "message": "Напомена: од 16 Маја 2024м недодељене ставке организације више нису видљиве у приказу Сви сефови и доступне су само преко Админ конзоле." }, "unassignedItemsBannerCTAPartOne": { "message": "Assign these items to a collection from the", @@ -3024,12 +3024,12 @@ "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "adminConsole": { - "message": "Admin Console" + "message": "Администраторска конзола" }, "errorAssigningTargetCollection": { - "message": "Error assigning target collection." + "message": "Грешка при додељивању циљне колекције." }, "errorAssigningTargetFolder": { - "message": "Error assigning target folder." + "message": "Грешка при додељивању циљне фасцикле." } } diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index d96e86b8d3..2b9ec59ec2 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Logga in eller skapa ett nytt konto för att komma åt ditt säkra valv." diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index 5d1b024c60..b6384bb840 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 794d0e6c22..7e1dda99be 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "ล็อกอิน หรือ สร้างบัญชีใหม่ เพื่อใช้งานตู้นิรภัยของคุณ" diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 8408253b86..8a8bb6ea60 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Güvenli kasanıza ulaşmak için giriş yapın veya yeni bir hesap oluşturun." diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index b590b92041..27293fc992 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Для доступу до сховища увійдіть в обліковий запис, або створіть новий." diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index ab1d0d515b..6e530412db 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -3,12 +3,12 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden - Trình Quản lý Mật khẩu", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "Ở nhà, ở cơ quan, hay trên đường đi, Bitwarden sẽ bảo mật tất cả mật khẩu, passkey, và thông tin cá nhân của bạn", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "Đăng nhập hoặc tạo tài khoản mới để truy cập kho lưu trữ của bạn." @@ -650,7 +650,7 @@ "message": "'Thông báo Thêm đăng nhập' sẽ tự động nhắc bạn lưu các đăng nhập mới vào hầm an toàn của bạn bất cứ khi nào bạn đăng nhập trang web lần đầu tiên." }, "addLoginNotificationDescAlt": { - "message": "Ask to add an item if one isn't found in your vault. Applies to all logged in accounts." + "message": "Đưa ra lựa chọn để thêm một mục nếu không tìm thấy mục đó trong hòm của bạn. Áp dụng với mọi tài khoản đăng nhập trên thiết bị." }, "showCardsCurrentTab": { "message": "Hiển thị thẻ trên trang Tab" @@ -685,13 +685,13 @@ "message": "Yêu cầu cập nhật mật khẩu đăng nhập khi phát hiện thay đổi trên trang web." }, "changedPasswordNotificationDescAlt": { - "message": "Ask to update a login's password when a change is detected on a website. Applies to all logged in accounts." + "message": "Đưa ra lựa chọn để cập nhật mật khẩu khi phát hiện có sự thay đổi trên trang web. Áp dụng với mọi tài khoản đăng nhập trên thiết bị." }, "enableUsePasskeys": { - "message": "Ask to save and use passkeys" + "message": "Đưa ra lựa chọn để lưu và sử dụng passkey" }, "usePasskeysDesc": { - "message": "Ask to save new passkeys or log in with passkeys stored in your vault. Applies to all logged in accounts." + "message": "Đưa ra lựa chọn để lưu passkey mới hoặc đăng nhập bằng passkey đã lưu trong hòm. Áp dụng với mọi tài khoản đăng nhập trên thiết bị." }, "notificationChangeDesc": { "message": "Bạn có muốn cập nhật mật khẩu này trên Bitwarden không?" @@ -712,7 +712,7 @@ "message": "Sử dụng một đúp chuột để truy cập vào việc tạo mật khẩu và thông tin đăng nhập phù hợp cho trang web. " }, "contextMenuItemDescAlt": { - "message": "Use a secondary click to access password generation and matching logins for the website. Applies to all logged in accounts." + "message": "Truy cập trình khởi tạo mật khẩu và các mục đăng nhập đã lưu của trang web bằng cách nhấn đúp chuột. Áp dụng với mọi tài khoản đăng nhập trên thiết bị." }, "defaultUriMatchDetection": { "message": "Phương thức kiểm tra URI mặc định", @@ -728,7 +728,7 @@ "message": "Thay đổi màu sắc ứng dụng." }, "themeDescAlt": { - "message": "Change the application's color theme. Applies to all logged in accounts." + "message": "Thay đổi tông màu giao diện của ứng dụng. Áp dụng với mọi tài khoản đăng nhập trên thiết bị." }, "dark": { "message": "Tối", @@ -1061,10 +1061,10 @@ "message": "Tắt cài đặt trình quản lý mật khẩu tích hợp trong trình duyệt của bạn để tránh xung đột." }, "turnOffBrowserBuiltInPasswordManagerSettingsLink": { - "message": "Edit browser settings." + "message": "Thay đổi cài đặt của trình duyệt." }, "autofillOverlayVisibilityOff": { - "message": "Off", + "message": "Tắt", "description": "Overlay setting select option for disabling autofill overlay" }, "autofillOverlayVisibilityOnFieldFocus": { @@ -1168,7 +1168,7 @@ "message": "Hiển thị một ảnh nhận dạng bên cạnh mỗi lần đăng nhập." }, "faviconDescAlt": { - "message": "Show a recognizable image next to each login. Applies to all logged in accounts." + "message": "Hiển thị một biểu tượng dễ nhận dạng bên cạnh mỗi mục đăng nhập. Áp dụng với mọi tài khoản đăng nhập trên thiết bị." }, "enableBadgeCounter": { "message": "Hiển thị biểu tượng bộ đếm" @@ -1500,7 +1500,7 @@ "message": "Mã PIN không hợp lệ." }, "tooManyInvalidPinEntryAttemptsLoggingOut": { - "message": "Too many invalid PIN entry attempts. Logging out." + "message": "Mã PIN bị gõ sai quá nhiều lần. Đang đăng xuất." }, "unlockWithBiometrics": { "message": "Mở khóa bằng sinh trắc học" diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index a2f856c31b..3cf2f96da1 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -3,12 +3,12 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden 密码管理器", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "无论是在家里、工作中还是在外出时,Bitwarden 都可以轻松地保护您的所有密码、通行密钥和敏感信息。", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "登录或者创建一个账户来访问您的安全密码库。" @@ -176,7 +176,7 @@ "message": "前往网页 App 吗?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "您可以在 Bitwarden 网页应用上更改您的主密码。" }, "fingerprintPhrase": { "message": "指纹短语", @@ -3010,17 +3010,17 @@ "message": "通行密钥已移除" }, "unassignedItemsBannerNotice": { - "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." + "message": "注意:未分配的组织项目在「所有密码库」视图中不再可见,只能通过管理控制台访问。" }, "unassignedItemsBannerSelfHostNotice": { - "message": "Notice: On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and will only be accessible via the Admin Console." + "message": "注意:从 2024 年 5 月 16 日起,未分配的组织项目在「所有密码库」视图中将不再可见,只能通过管理控制台访问。" }, "unassignedItemsBannerCTAPartOne": { "message": "Assign these items to a collection from the", "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "unassignedItemsBannerCTAPartTwo": { - "message": "to make them visible.", + "message": "以使其可见。", "description": "This will be part of a larger sentence, which will read like so: Assign these items to a collection from the Admin Console to make them visible." }, "adminConsole": { diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 1ecfdfc50e..eb35cd08c7 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -7,8 +7,8 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.", - "description": "Extension description" + "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { "message": "登入或建立帳戶以存取您的安全密碼庫。" diff --git a/apps/browser/src/auth/background/service-factories/device-trust-crypto-service.factory.ts b/apps/browser/src/auth/background/service-factories/device-trust-service.factory.ts similarity index 79% rename from apps/browser/src/auth/background/service-factories/device-trust-crypto-service.factory.ts rename to apps/browser/src/auth/background/service-factories/device-trust-service.factory.ts index cac6f9bbe8..106bcbcf72 100644 --- a/apps/browser/src/auth/background/service-factories/device-trust-crypto-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/device-trust-service.factory.ts @@ -1,5 +1,5 @@ -import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; -import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device-trust-crypto.service.implementation"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesApiServiceInitOptions, @@ -52,9 +52,9 @@ import { userDecryptionOptionsServiceFactory, } from "./user-decryption-options-service.factory"; -type DeviceTrustCryptoServiceFactoryOptions = FactoryOptions; +type DeviceTrustServiceFactoryOptions = FactoryOptions; -export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactoryOptions & +export type DeviceTrustServiceInitOptions = DeviceTrustServiceFactoryOptions & KeyGenerationServiceInitOptions & CryptoFunctionServiceInitOptions & CryptoServiceInitOptions & @@ -67,16 +67,16 @@ export type DeviceTrustCryptoServiceInitOptions = DeviceTrustCryptoServiceFactor SecureStorageServiceInitOptions & UserDecryptionOptionsServiceInitOptions; -export function deviceTrustCryptoServiceFactory( - cache: { deviceTrustCryptoService?: DeviceTrustCryptoServiceAbstraction } & CachedServices, - opts: DeviceTrustCryptoServiceInitOptions, -): Promise { +export function deviceTrustServiceFactory( + cache: { deviceTrustService?: DeviceTrustServiceAbstraction } & CachedServices, + opts: DeviceTrustServiceInitOptions, +): Promise { return factory( cache, - "deviceTrustCryptoService", + "deviceTrustService", opts, async () => - new DeviceTrustCryptoService( + new DeviceTrustService( await keyGenerationServiceFactory(cache, opts), await cryptoFunctionServiceFactory(cache, opts), await cryptoServiceFactory(cache, opts), diff --git a/apps/browser/src/auth/background/service-factories/kdf-config-service.factory.ts b/apps/browser/src/auth/background/service-factories/kdf-config-service.factory.ts new file mode 100644 index 0000000000..eb5ba3a264 --- /dev/null +++ b/apps/browser/src/auth/background/service-factories/kdf-config-service.factory.ts @@ -0,0 +1,28 @@ +import { KdfConfigService as AbstractKdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; +import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service"; + +import { + FactoryOptions, + CachedServices, + factory, +} from "../../../platform/background/service-factories/factory-options"; +import { + StateProviderInitOptions, + stateProviderFactory, +} from "../../../platform/background/service-factories/state-provider.factory"; + +type KdfConfigServiceFactoryOptions = FactoryOptions; + +export type KdfConfigServiceInitOptions = KdfConfigServiceFactoryOptions & StateProviderInitOptions; + +export function kdfConfigServiceFactory( + cache: { kdfConfigService?: AbstractKdfConfigService } & CachedServices, + opts: KdfConfigServiceInitOptions, +): Promise { + return factory( + cache, + "kdfConfigService", + opts, + async () => new KdfConfigService(await stateProviderFactory(cache, opts)), + ); +} diff --git a/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts b/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts index 32dedd29b8..e545a3a828 100644 --- a/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts @@ -69,9 +69,10 @@ import { AuthRequestServiceInitOptions, } from "./auth-request-service.factory"; import { - deviceTrustCryptoServiceFactory, - DeviceTrustCryptoServiceInitOptions, -} from "./device-trust-crypto-service.factory"; + deviceTrustServiceFactory, + DeviceTrustServiceInitOptions, +} from "./device-trust-service.factory"; +import { kdfConfigServiceFactory, KdfConfigServiceInitOptions } from "./kdf-config-service.factory"; import { keyConnectorServiceFactory, KeyConnectorServiceInitOptions, @@ -106,11 +107,12 @@ export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions EncryptServiceInitOptions & PolicyServiceInitOptions & PasswordStrengthServiceInitOptions & - DeviceTrustCryptoServiceInitOptions & + DeviceTrustServiceInitOptions & AuthRequestServiceInitOptions & UserDecryptionOptionsServiceInitOptions & GlobalStateProviderInitOptions & BillingAccountProfileStateServiceInitOptions & + KdfConfigServiceInitOptions & TaskSchedulerServiceInitOptions; export function loginStrategyServiceFactory( @@ -140,11 +142,12 @@ export function loginStrategyServiceFactory( await encryptServiceFactory(cache, opts), await passwordStrengthServiceFactory(cache, opts), await policyServiceFactory(cache, opts), - await deviceTrustCryptoServiceFactory(cache, opts), + await deviceTrustServiceFactory(cache, opts), await authRequestServiceFactory(cache, opts), await internalUserDecryptionOptionServiceFactory(cache, opts), await globalStateProviderFactory(cache, opts), await billingAccountProfileStateServiceFactory(cache, opts), + await kdfConfigServiceFactory(cache, opts), await taskSchedulerServiceFactory(cache, opts), ), ); diff --git a/apps/browser/src/auth/background/service-factories/pin-crypto-service.factory.ts b/apps/browser/src/auth/background/service-factories/pin-crypto-service.factory.ts index f5360f48fa..db16245f67 100644 --- a/apps/browser/src/auth/background/service-factories/pin-crypto-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/pin-crypto-service.factory.ts @@ -22,13 +22,16 @@ import { stateServiceFactory, } from "../../../platform/background/service-factories/state-service.factory"; +import { KdfConfigServiceInitOptions, kdfConfigServiceFactory } from "./kdf-config-service.factory"; + type PinCryptoServiceFactoryOptions = FactoryOptions; export type PinCryptoServiceInitOptions = PinCryptoServiceFactoryOptions & StateServiceInitOptions & CryptoServiceInitOptions & VaultTimeoutSettingsServiceInitOptions & - LogServiceInitOptions; + LogServiceInitOptions & + KdfConfigServiceInitOptions; export function pinCryptoServiceFactory( cache: { pinCryptoService?: PinCryptoServiceAbstraction } & CachedServices, @@ -44,6 +47,7 @@ export function pinCryptoServiceFactory( await cryptoServiceFactory(cache, opts), await vaultTimeoutSettingsServiceFactory(cache, opts), await logServiceFactory(cache, opts), + await kdfConfigServiceFactory(cache, opts), ), ); } diff --git a/apps/browser/src/auth/background/service-factories/two-factor-service.factory.ts b/apps/browser/src/auth/background/service-factories/two-factor-service.factory.ts index 1d79bbbaf1..5af5eb0017 100644 --- a/apps/browser/src/auth/background/service-factories/two-factor-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/two-factor-service.factory.ts @@ -1,11 +1,13 @@ import { TwoFactorService as AbstractTwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service"; +import { GlobalStateProvider } from "@bitwarden/common/platform/state"; import { FactoryOptions, CachedServices, factory, } from "../../../platform/background/service-factories/factory-options"; +import { globalStateProviderFactory } from "../../../platform/background/service-factories/global-state-provider.factory"; import { I18nServiceInitOptions, i18nServiceFactory, @@ -19,7 +21,8 @@ type TwoFactorServiceFactoryOptions = FactoryOptions; export type TwoFactorServiceInitOptions = TwoFactorServiceFactoryOptions & I18nServiceInitOptions & - PlatformUtilsServiceInitOptions; + PlatformUtilsServiceInitOptions & + GlobalStateProvider; export async function twoFactorServiceFactory( cache: { twoFactorService?: AbstractTwoFactorService } & CachedServices, @@ -33,6 +36,7 @@ export async function twoFactorServiceFactory( new TwoFactorService( await i18nServiceFactory(cache, opts), await platformUtilsServiceFactory(cache, opts), + await globalStateProviderFactory(cache, opts), ), ); service.init(); diff --git a/apps/browser/src/auth/background/service-factories/user-verification-service.factory.ts b/apps/browser/src/auth/background/service-factories/user-verification-service.factory.ts index a8b67b21ca..d6f9ce7624 100644 --- a/apps/browser/src/auth/background/service-factories/user-verification-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/user-verification-service.factory.ts @@ -32,6 +32,7 @@ import { } from "../../../platform/background/service-factories/state-service.factory"; import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory"; +import { KdfConfigServiceInitOptions, kdfConfigServiceFactory } from "./kdf-config-service.factory"; import { internalMasterPasswordServiceFactory, MasterPasswordServiceInitOptions, @@ -59,7 +60,8 @@ export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryO PinCryptoServiceInitOptions & LogServiceInitOptions & VaultTimeoutSettingsServiceInitOptions & - PlatformUtilsServiceInitOptions; + PlatformUtilsServiceInitOptions & + KdfConfigServiceInitOptions; export function userVerificationServiceFactory( cache: { userVerificationService?: AbstractUserVerificationService } & CachedServices, @@ -82,6 +84,7 @@ export function userVerificationServiceFactory( await logServiceFactory(cache, opts), await vaultTimeoutSettingsServiceFactory(cache, opts), await platformUtilsServiceFactory(cache, opts), + await kdfConfigServiceFactory(cache, opts), ), ); } diff --git a/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.ts b/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.ts index a73ec3e1f6..e5a3b8f8f5 100644 --- a/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.ts +++ b/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.ts @@ -110,7 +110,7 @@ export class AccountSwitcherService { }), ); - // Create a reusable observable that listens to the the switchAccountFinish message and returns the userId from the message + // Create a reusable observable that listens to the switchAccountFinish message and returns the userId from the message this.switchAccountFinished$ = fromChromeEvent<[message: { command: string; userId: string }]>( chrome.runtime.onMessage, ).pipe( diff --git a/apps/browser/src/auth/popup/lock.component.ts b/apps/browser/src/auth/popup/lock.component.ts index 16c32337cf..4d47417df6 100644 --- a/apps/browser/src/auth/popup/lock.component.ts +++ b/apps/browser/src/auth/popup/lock.component.ts @@ -11,7 +11,8 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs 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 { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -60,12 +61,13 @@ export class LockComponent extends BaseLockComponent { passwordStrengthService: PasswordStrengthServiceAbstraction, private authService: AuthService, dialogService: DialogService, - deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + deviceTrustService: DeviceTrustServiceAbstraction, userVerificationService: UserVerificationService, pinCryptoService: PinCryptoServiceAbstraction, private routerService: BrowserRouterService, biometricStateService: BiometricStateService, accountService: AccountService, + kdfConfigService: KdfConfigService, ) { super( masterPasswordService, @@ -85,11 +87,12 @@ export class LockComponent extends BaseLockComponent { policyService, passwordStrengthService, dialogService, - deviceTrustCryptoService, + deviceTrustService, userVerificationService, pinCryptoService, biometricStateService, accountService, + kdfConfigService, ); this.successRoute = "/tabs/current"; this.isInitialLockScreen = (window as any).previousPopupUrl == null; diff --git a/apps/browser/src/auth/popup/login-via-auth-request.component.ts b/apps/browser/src/auth/popup/login-via-auth-request.component.ts index 52f311ce7b..158296058e 100644 --- a/apps/browser/src/auth/popup/login-via-auth-request.component.ts +++ b/apps/browser/src/auth/popup/login-via-auth-request.component.ts @@ -12,7 +12,7 @@ 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 { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; 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"; @@ -47,7 +47,7 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { stateService: StateService, loginEmailService: LoginEmailServiceAbstraction, syncService: SyncService, - deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + deviceTrustService: DeviceTrustServiceAbstraction, authRequestService: AuthRequestServiceAbstraction, loginStrategyService: LoginStrategyServiceAbstraction, accountService: AccountService, @@ -69,7 +69,7 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { validationService, stateService, loginEmailService, - deviceTrustCryptoService, + deviceTrustService, authRequestService, loginStrategyService, accountService, diff --git a/apps/browser/src/auth/popup/two-factor-options.component.ts b/apps/browser/src/auth/popup/two-factor-options.component.ts index bad2e4a9e7..6191d277ad 100644 --- a/apps/browser/src/auth/popup/two-factor-options.component.ts +++ b/apps/browser/src/auth/popup/two-factor-options.component.ts @@ -2,7 +2,10 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent } from "@bitwarden/angular/auth/components/two-factor-options.component"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { + TwoFactorProviderDetails, + TwoFactorService, +} from "@bitwarden/common/auth/abstractions/two-factor.service"; 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"; @@ -27,9 +30,9 @@ export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent { this.navigateTo2FA(); } - choose(p: any) { - super.choose(p); - this.twoFactorService.setSelectedProvider(p.type); + override async choose(p: TwoFactorProviderDetails) { + await super.choose(p); + await this.twoFactorService.setSelectedProvider(p.type); this.navigateTo2FA(); } diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index 8f85d65692..10e2d84361 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -130,7 +130,9 @@ export default class AutofillService implements AutofillServiceInterface { if (triggeringOnPageLoad && autoFillOnPageLoadIsEnabled) { injectedScripts.push("autofiller.js"); - } else { + } + + if (!triggeringOnPageLoad) { await this.scriptInjectorService.inject({ tabId: tab.id, injectDetails: { file: "content/content-message-handler.js", runAt: "document_start" }, diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 6c631d6d19..76a11ae22e 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -1,10 +1,8 @@ -import { Subject, firstValueFrom, merge } from "rxjs"; +import { Subject, firstValueFrom, merge, timeout } from "rxjs"; import { PinCryptoServiceAbstraction, PinCryptoService, - LoginStrategyServiceAbstraction, - LoginStrategyService, InternalUserDecryptionOptionsServiceAbstraction, UserDecryptionOptionsService, AuthRequestServiceAbstraction, @@ -30,14 +28,14 @@ import { ProviderService } from "@bitwarden/common/admin-console/services/provid import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service"; -import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; +import { KdfConfigService as kdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction"; import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -45,14 +43,14 @@ import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/for import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; -import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device-trust-crypto.service.implementation"; +import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; +import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service"; import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service"; import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service"; import { @@ -73,6 +71,7 @@ import { } from "@bitwarden/common/autofill/services/user-notification-settings.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service"; +import { ClientType } from "@bitwarden/common/enums"; import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service"; import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -277,7 +276,6 @@ export default class MainBackground { containerService: ContainerService; auditService: AuditServiceAbstraction; authService: AuthServiceAbstraction; - loginStrategyService: LoginStrategyServiceAbstraction; loginEmailService: LoginEmailServiceAbstraction; importApiService: ImportApiServiceAbstraction; importService: ImportServiceAbstraction; @@ -301,7 +299,6 @@ export default class MainBackground { providerService: ProviderServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction; userVerificationService: UserVerificationServiceAbstraction; - twoFactorService: TwoFactorServiceAbstraction; vaultFilterService: VaultFilterService; usernameGenerationService: UsernameGenerationServiceAbstraction; encryptService: EncryptService; @@ -320,7 +317,7 @@ export default class MainBackground { configApiService: ConfigApiServiceAbstraction; devicesApiService: DevicesApiServiceAbstraction; devicesService: DevicesServiceAbstraction; - deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction; + deviceTrustService: DeviceTrustServiceAbstraction; authRequestService: AuthRequestServiceAbstraction; accountService: AccountServiceAbstraction; globalStateProvider: GlobalStateProvider; @@ -342,6 +339,7 @@ export default class MainBackground { intraprocessMessagingSubject: Subject>; userKeyInitService: UserKeyInitService; scriptInjectorService: BrowserScriptInjectorService; + kdfConfigService: kdfConfigServiceAbstraction; onUpdatedRan: boolean; onReplacedRan: boolean; @@ -496,7 +494,7 @@ export default class MainBackground { this.accountService, this.singleUserStateProvider, ); - this.derivedStateProvider = new BackgroundDerivedStateProvider(storageServiceProvider); + this.derivedStateProvider = new BackgroundDerivedStateProvider(); this.stateProvider = new DefaultStateProvider( this.activeUserStateProvider, this.singleUserStateProvider, @@ -540,6 +538,7 @@ export default class MainBackground { this.storageService, this.logService, new MigrationBuilderService(), + ClientType.Browser, ); this.stateService = new DefaultBrowserStateService( @@ -559,6 +558,9 @@ export default class MainBackground { this.masterPasswordService = new MasterPasswordService(this.stateProvider); this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider); + + this.kdfConfigService = new KdfConfigService(this.stateProvider); + this.cryptoService = new BrowserCryptoService( this.masterPasswordService, this.keyGenerationService, @@ -570,6 +572,7 @@ export default class MainBackground { this.accountService, this.stateProvider, this.biometricStateService, + this.kdfConfigService, ); this.appIdService = new AppIdService(this.globalStateProvider); @@ -624,12 +627,10 @@ export default class MainBackground { this.stateService, ); - this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService); - this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); this.devicesApiService = new DevicesApiServiceImplementation(this.apiService); - this.deviceTrustCryptoService = new DeviceTrustCryptoService( + this.deviceTrustService = new DeviceTrustService( this.keyGenerationService, this.cryptoFunctionService, this.cryptoService, @@ -669,32 +670,6 @@ export default class MainBackground { this.loginEmailService = new LoginEmailService(this.stateProvider); - this.loginStrategyService = new LoginStrategyService( - this.accountService, - this.masterPasswordService, - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.keyConnectorService, - this.environmentService, - this.stateService, - this.twoFactorService, - this.i18nService, - this.encryptService, - this.passwordStrengthService, - this.policyService, - this.deviceTrustCryptoService, - this.authRequestService, - this.userDecryptionOptionsService, - this.globalStateProvider, - this.billingAccountProfileStateService, - this.taskSchedulerService, - ); - this.ssoLoginService = new SsoLoginService(this.stateProvider); this.userVerificationApiService = new UserVerificationApiService(this.apiService); @@ -743,6 +718,7 @@ export default class MainBackground { this.cryptoService, this.vaultTimeoutSettingsService, this.logService, + this.kdfConfigService, ); this.userVerificationService = new UserVerificationService( @@ -757,6 +733,7 @@ export default class MainBackground { this.logService, this.vaultTimeoutSettingsService, this.platformUtilsService, + this.kdfConfigService, ); this.vaultFilterService = new VaultFilterService( @@ -831,6 +808,7 @@ export default class MainBackground { this.avatarService, logoutCallback, this.billingAccountProfileStateService, + this.tokenService, ); this.eventUploadService = new EventUploadService( this.apiService, @@ -879,7 +857,7 @@ export default class MainBackground { this.cipherService, this.cryptoService, this.cryptoFunctionService, - this.stateService, + this.kdfConfigService, ); this.organizationVaultExportService = new OrganizationVaultExportService( @@ -887,8 +865,8 @@ export default class MainBackground { this.apiService, this.cryptoService, this.cryptoFunctionService, - this.stateService, this.collectionService, + this.kdfConfigService, ); this.exportService = new VaultExportService( @@ -1117,15 +1095,15 @@ export default class MainBackground { async bootstrap() { this.containerService.attachToGlobal(self); - await this.stateService.init({ runMigrations: !this.isPrivateMode }); + // Only the "true" background should run migrations + await this.stateService.init({ runMigrations: !this.popupOnlyContext }); // This is here instead of in in the InitService b/c we don't plan for // side effects to run in the Browser InitService. this.userKeyInitService.listenForActiveUserChangesToSetUserKey(); await (this.i18nService as I18nService).init(); - await (this.eventUploadService as EventUploadService).init(true); - this.twoFactorService.init(); + (this.eventUploadService as EventUploadService).init(true); if (this.popupOnlyContext) { return; @@ -1247,7 +1225,18 @@ export default class MainBackground { } async logout(expired: boolean, userId?: UserId) { - userId ??= (await firstValueFrom(this.accountService.activeAccount$))?.id; + userId ??= ( + await firstValueFrom( + this.accountService.activeAccount$.pipe( + timeout({ + first: 2000, + with: () => { + throw new Error("No active account found to logout"); + }, + }), + ), + ) + )?.id; await this.eventUploadService.uploadEvents(userId as UserId); diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index f457889e96..14eb228fb0 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -10,7 +10,7 @@ import { SystemService } from "@bitwarden/common/platform/abstractions/system.se import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherType } from "@bitwarden/common/vault/enums"; -import { MessageListener } from "../../../../libs/common/src/platform/messaging"; +import { MessageListener, isExternalMessage } from "../../../../libs/common/src/platform/messaging"; import { closeUnlockPopout, openSsoAuthResultPopout, @@ -85,7 +85,11 @@ export default class RuntimeBackground { this.messageListener.allMessages$ .pipe( mergeMap(async (message: any) => { - await this.processMessage(message); + try { + await this.processMessage(message); + } catch (err) { + this.logService.error(err); + } }), ) .subscribe(); @@ -266,7 +270,9 @@ export default class RuntimeBackground { break; } case "reloadPopup": - this.messagingService.send("reloadPopup"); + if (isExternalMessage(msg)) { + this.messagingService.send("reloadPopup"); + } break; case "emailVerificationRequired": this.messagingService.send("showDialog", { diff --git a/apps/browser/src/platform/background/service-factories/crypto-service.factory.ts b/apps/browser/src/platform/background/service-factories/crypto-service.factory.ts index ed4fde162c..1f848e1d0f 100644 --- a/apps/browser/src/platform/background/service-factories/crypto-service.factory.ts +++ b/apps/browser/src/platform/background/service-factories/crypto-service.factory.ts @@ -4,6 +4,10 @@ import { AccountServiceInitOptions, accountServiceFactory, } from "../../../auth/background/service-factories/account-service.factory"; +import { + KdfConfigServiceInitOptions, + kdfConfigServiceFactory, +} from "../../../auth/background/service-factories/kdf-config-service.factory"; import { internalMasterPasswordServiceFactory, MasterPasswordServiceInitOptions, @@ -18,7 +22,10 @@ import { } from "../../background/service-factories/log-service.factory"; import { BrowserCryptoService } from "../../services/browser-crypto.service"; -import { biometricStateServiceFactory } from "./biometric-state-service.factory"; +import { + BiometricStateServiceInitOptions, + biometricStateServiceFactory, +} from "./biometric-state-service.factory"; import { cryptoFunctionServiceFactory, CryptoFunctionServiceInitOptions, @@ -46,7 +53,9 @@ export type CryptoServiceInitOptions = CryptoServiceFactoryOptions & LogServiceInitOptions & StateServiceInitOptions & AccountServiceInitOptions & - StateProviderInitOptions; + StateProviderInitOptions & + BiometricStateServiceInitOptions & + KdfConfigServiceInitOptions; export function cryptoServiceFactory( cache: { cryptoService?: AbstractCryptoService } & CachedServices, @@ -68,6 +77,7 @@ export function cryptoServiceFactory( await accountServiceFactory(cache, opts), await stateProviderFactory(cache, opts), await biometricStateServiceFactory(cache, opts), + await kdfConfigServiceFactory(cache, opts), ), ); } diff --git a/apps/browser/src/platform/background/service-factories/derived-state-provider.factory.ts b/apps/browser/src/platform/background/service-factories/derived-state-provider.factory.ts index 4025d01950..3c3900144b 100644 --- a/apps/browser/src/platform/background/service-factories/derived-state-provider.factory.ts +++ b/apps/browser/src/platform/background/service-factories/derived-state-provider.factory.ts @@ -3,15 +3,10 @@ import { DerivedStateProvider } from "@bitwarden/common/platform/state"; import { BackgroundDerivedStateProvider } from "../../state/background-derived-state.provider"; import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - StorageServiceProviderInitOptions, - storageServiceProviderFactory, -} from "./storage-service-provider.factory"; type DerivedStateProviderFactoryOptions = FactoryOptions; -export type DerivedStateProviderInitOptions = DerivedStateProviderFactoryOptions & - StorageServiceProviderInitOptions; +export type DerivedStateProviderInitOptions = DerivedStateProviderFactoryOptions; export async function derivedStateProviderFactory( cache: { derivedStateProvider?: DerivedStateProvider } & CachedServices, @@ -21,7 +16,6 @@ export async function derivedStateProviderFactory( cache, "derivedStateProvider", opts, - async () => - new BackgroundDerivedStateProvider(await storageServiceProviderFactory(cache, opts)), + async () => new BackgroundDerivedStateProvider(), ); } diff --git a/apps/browser/src/platform/background/service-factories/migration-runner.factory.ts b/apps/browser/src/platform/background/service-factories/migration-runner.factory.ts index a49699a615..090531f7cf 100644 --- a/apps/browser/src/platform/background/service-factories/migration-runner.factory.ts +++ b/apps/browser/src/platform/background/service-factories/migration-runner.factory.ts @@ -1,3 +1,4 @@ +import { ClientType } from "@bitwarden/common/enums"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; @@ -27,6 +28,7 @@ export async function migrationRunnerFactory( await diskStorageServiceFactory(cache, opts), await logServiceFactory(cache, opts), new MigrationBuilderService(), + ClientType.Browser, ), ); } diff --git a/apps/browser/src/platform/background/service-factories/state-service.factory.ts b/apps/browser/src/platform/background/service-factories/state-service.factory.ts index 5567e00990..026a29668e 100644 --- a/apps/browser/src/platform/background/service-factories/state-service.factory.ts +++ b/apps/browser/src/platform/background/service-factories/state-service.factory.ts @@ -30,7 +30,6 @@ import { type StateServiceFactoryOptions = FactoryOptions & { stateServiceOptions: { - useAccountCache?: boolean; stateFactory: StateFactory; }; }; @@ -64,7 +63,6 @@ export async function stateServiceFactory( await environmentServiceFactory(cache, opts), await tokenServiceFactory(cache, opts), await migrationRunnerFactory(cache, opts), - opts.stateServiceOptions.useAccountCache, ), ); // TODO: If we run migration through a chrome installed/updated event we can turn off running migrations diff --git a/apps/browser/src/platform/browser/browser-api.ts b/apps/browser/src/platform/browser/browser-api.ts index b793777d8b..f536eb8312 100644 --- a/apps/browser/src/platform/browser/browser-api.ts +++ b/apps/browser/src/platform/browser/browser-api.ts @@ -238,10 +238,6 @@ export class BrowserApi { return typeof window !== "undefined" && window === BrowserApi.getBackgroundPage(); } - static getApplicationVersion(): string { - return chrome.runtime.getManifest().version; - } - /** * Gets the extension views that match the given properties. This method is not * available within background service worker. As a result, it will return an diff --git a/apps/browser/src/platform/popup/browser-popup-utils.spec.ts b/apps/browser/src/platform/popup/browser-popup-utils.spec.ts index e84cd19a45..c2d33369bd 100644 --- a/apps/browser/src/platform/popup/browser-popup-utils.spec.ts +++ b/apps/browser/src/platform/popup/browser-popup-utils.spec.ts @@ -203,7 +203,7 @@ describe("BrowserPopupUtils", () => { expect(BrowserPopupUtils["buildPopoutUrl"]).not.toHaveBeenCalled(); }); - it("replaces any existing `uilocation=` query params within the passed extension url path to state the the uilocaiton is a popup", async () => { + it("replaces any existing `uilocation=` query params within the passed extension url path to state the uilocation is a popup", async () => { const url = "popup/index.html?uilocation=sidebar#/tabs/vault"; jest.spyOn(BrowserPopupUtils as any, "isSingleActionPopoutOpen").mockResolvedValueOnce(false); diff --git a/apps/browser/src/platform/popup/layout/popup-footer.component.html b/apps/browser/src/platform/popup/layout/popup-footer.component.html new file mode 100644 index 0000000000..2cbbca79c0 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-footer.component.html @@ -0,0 +1,9 @@ +
+
+
+ +
+
+
diff --git a/apps/browser/src/platform/popup/layout/popup-footer.component.ts b/apps/browser/src/platform/popup/layout/popup-footer.component.ts new file mode 100644 index 0000000000..826a1d1c60 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-footer.component.ts @@ -0,0 +1,9 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "popup-footer", + templateUrl: "popup-footer.component.html", + standalone: true, + imports: [], +}) +export class PopupFooterComponent {} diff --git a/apps/browser/src/platform/popup/layout/popup-header.component.html b/apps/browser/src/platform/popup/layout/popup-header.component.html new file mode 100644 index 0000000000..c0894f8168 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-header.component.html @@ -0,0 +1,19 @@ +
+
+
+ +

{{ pageTitle }}

+
+
+ +
+
+
diff --git a/apps/browser/src/platform/popup/layout/popup-header.component.ts b/apps/browser/src/platform/popup/layout/popup-header.component.ts new file mode 100644 index 0000000000..f2f8eb95af --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-header.component.ts @@ -0,0 +1,34 @@ +import { BooleanInput, coerceBooleanProperty } from "@angular/cdk/coercion"; +import { CommonModule, Location } from "@angular/common"; +import { Component, Input } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { IconButtonModule, TypographyModule } from "@bitwarden/components"; + +@Component({ + selector: "popup-header", + templateUrl: "popup-header.component.html", + standalone: true, + imports: [TypographyModule, CommonModule, IconButtonModule, JslibModule], +}) +export class PopupHeaderComponent { + /** Display the back button, which uses Location.back() to go back one page in history */ + @Input() + get showBackButton() { + return this._showBackButton; + } + set showBackButton(value: BooleanInput) { + this._showBackButton = coerceBooleanProperty(value); + } + + private _showBackButton = false; + + /** Title string that will be inserted as an h1 */ + @Input({ required: true }) pageTitle: string; + + constructor(private location: Location) {} + + back() { + this.location.back(); + } +} diff --git a/apps/browser/src/platform/popup/layout/popup-layout.mdx b/apps/browser/src/platform/popup/layout/popup-layout.mdx new file mode 100644 index 0000000000..91f7dab277 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-layout.mdx @@ -0,0 +1,138 @@ +import { Meta, Story, Canvas } from "@storybook/addon-docs"; + +import * as stories from "./popup-layout.stories"; + + + +Please note that because these stories use `router-outlet`, there are issues with rendering content +when Light & Dark mode is selected. The stories are best viewed by selecting one color mode. + +# Popup Tab Navigation + +The popup tab navigation component composes together the popup page and the bottom tab navigation +footer. This component is intended to be used a level _above_ each extension tab's page code. + +The navigation footer contains the 4 main page links for the browser extension. It uses the Angular +router to determine which page is currently active, and style the button appropriately. Clicking on +the buttons will navigate to the correct route. The navigation footer has a max-width built in so +that the page looks nice when the extension is popped out. + +Long button names will be ellipsed. + +Usage example: + +```html + + + +``` + +# Popup Page + +The popup page handles positioning a page's `header` and `footer` elements, and inserting the rest +of the content into the `main` element with scroll. There is also a max-width built in so that the +page looks nice when the extension is popped out. + +**Slots** + +- `header` + - Use `popup-header` component. + - Every page should have a header. +- `footer` + - Use the `popup-footer` component. + - Not every page will have a footer. +- default + - Whatever content you want in `main`. + +Basic usage example: + +```html + + +
This is content
+ +
+``` + +## Popup header + +**Args** + +- `pageTitle`: required + - Inserts title as an `h1`. +- `showBackButton`: optional, defaults to `false` + - Toggles the back button to appear. The back button uses `Location.back()` to navigate back one + page in history. + +**Slots** + +- `end` + - Use to insert one or more interactive elements. + - The header handles the spacing between elements passed to the `end` slot. + +Usage example: + +```html + + + + + + +``` + +Common interactive elements to insert into the `end` slot are: + +- `app-current-account`: shows current account and switcher +- `app-pop-out`: shows popout button when the extension is not already popped out +- "Add" button: this can be accomplished with the Button component and any custom functionality for + that particular page + +## Popup footer + +Popup footer should be used when the page displays action buttons. It functions similarly to the +Dialog footer in that the calling code is responsible for passing in the different buttons that need +to be rendered. + +Usage example: + +```html + + + + +``` + +# Page types + +There are a few types of pages that are used in the browser extension. + +View the story source code to see examples of how to construct these types of pages. + +## Extension Tab + +Example of wrapping an extension page in the `popup-tab-navigation` component. + + + + + +## Extension Page + +Examples of using just the `popup-page` component, without and with a footer. + + + + + + + + + +## Popped out + +When the browser extension is popped out, the "popout" button should not be passed to the header. + + + + diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts new file mode 100644 index 0000000000..1b10e50c0c --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -0,0 +1,367 @@ +import { CommonModule } from "@angular/common"; +import { Component, importProvidersFrom } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { + AvatarModule, + ButtonModule, + I18nMockService, + IconButtonModule, +} from "@bitwarden/components"; + +import { PopupFooterComponent } from "./popup-footer.component"; +import { PopupHeaderComponent } from "./popup-header.component"; +import { PopupPageComponent } from "./popup-page.component"; +import { PopupTabNavigationComponent } from "./popup-tab-navigation.component"; + +@Component({ + selector: "extension-container", + template: ` +
+ +
+ `, + standalone: true, +}) +class ExtensionContainerComponent {} + +@Component({ + selector: "vault-placeholder", + template: ` +
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item
+
vault item last item
+ `, + standalone: true, +}) +class VaultComponent {} + +@Component({ + selector: "generator-placeholder", + template: `
generator stuff here
`, + standalone: true, +}) +class GeneratorComponent {} + +@Component({ + selector: "send-placeholder", + template: `
send some stuff
`, + standalone: true, +}) +class SendComponent {} + +@Component({ + selector: "settings-placeholder", + template: `
change your settings
`, + standalone: true, +}) +class SettingsComponent {} + +@Component({ + selector: "mock-add-button", + template: ` + + `, + standalone: true, + imports: [ButtonModule], +}) +class MockAddButtonComponent {} + +@Component({ + selector: "mock-popout-button", + template: ` + + `, + standalone: true, + imports: [IconButtonModule], +}) +class MockPopoutButtonComponent {} + +@Component({ + selector: "mock-current-account", + template: ` + + `, + standalone: true, + imports: [AvatarModule], +}) +class MockCurrentAccountComponent {} + +@Component({ + selector: "mock-vault-page", + template: ` + + + + + + + + + + + `, + standalone: true, + imports: [ + PopupPageComponent, + PopupHeaderComponent, + MockAddButtonComponent, + MockPopoutButtonComponent, + MockCurrentAccountComponent, + VaultComponent, + ], +}) +class MockVaultPageComponent {} + +@Component({ + selector: "mock-vault-page-popped", + template: ` + + + + + + + + + + `, + standalone: true, + imports: [ + PopupPageComponent, + PopupHeaderComponent, + MockAddButtonComponent, + MockPopoutButtonComponent, + MockCurrentAccountComponent, + VaultComponent, + ], +}) +class MockVaultPagePoppedComponent {} + +@Component({ + selector: "mock-generator-page", + template: ` + + + + + + + + + + + `, + standalone: true, + imports: [ + PopupPageComponent, + PopupHeaderComponent, + MockAddButtonComponent, + MockPopoutButtonComponent, + MockCurrentAccountComponent, + GeneratorComponent, + ], +}) +class MockGeneratorPageComponent {} + +@Component({ + selector: "mock-send-page", + template: ` + + + + + + + + + + + `, + standalone: true, + imports: [ + PopupPageComponent, + PopupHeaderComponent, + MockAddButtonComponent, + MockPopoutButtonComponent, + MockCurrentAccountComponent, + SendComponent, + ], +}) +class MockSendPageComponent {} + +@Component({ + selector: "mock-settings-page", + template: ` + + + + + + + + + + + `, + standalone: true, + imports: [ + PopupPageComponent, + PopupHeaderComponent, + MockAddButtonComponent, + MockPopoutButtonComponent, + MockCurrentAccountComponent, + SettingsComponent, + ], +}) +class MockSettingsPageComponent {} + +@Component({ + selector: "mock-vault-subpage", + template: ` + + + + + + + + + + + + + `, + standalone: true, + imports: [ + PopupPageComponent, + PopupHeaderComponent, + PopupFooterComponent, + ButtonModule, + MockAddButtonComponent, + MockPopoutButtonComponent, + MockCurrentAccountComponent, + VaultComponent, + ], +}) +class MockVaultSubpageComponent {} + +export default { + title: "Browser/Popup Layout", + component: PopupPageComponent, + decorators: [ + moduleMetadata({ + imports: [ + PopupTabNavigationComponent, + CommonModule, + RouterModule, + ExtensionContainerComponent, + MockVaultSubpageComponent, + MockVaultPageComponent, + MockSendPageComponent, + MockGeneratorPageComponent, + MockSettingsPageComponent, + MockVaultPagePoppedComponent, + ], + providers: [ + { + provide: I18nService, + useFactory: () => { + return new I18nMockService({ + back: "Back", + }); + }, + }, + ], + }), + applicationConfig({ + providers: [ + importProvidersFrom( + RouterModule.forRoot( + [ + { path: "", redirectTo: "vault", pathMatch: "full" }, + { path: "vault", component: MockVaultPageComponent }, + { path: "generator", component: MockGeneratorPageComponent }, + { path: "send", component: MockSendPageComponent }, + { path: "settings", component: MockSettingsPageComponent }, + // in case you are coming from a story that also uses the router + { path: "**", redirectTo: "vault" }, + ], + { useHash: true }, + ), + ), + ], + }), + ], +} as Meta; + +type Story = StoryObj; + +export const PopupTabNavigation: Story = { + render: (args) => ({ + props: args, + template: /* HTML */ ` + + + + + + `, + }), +}; + +export const PopupPage: Story = { + render: (args) => ({ + props: args, + template: /* HTML */ ` + + + + `, + }), +}; + +export const PopupPageWithFooter: Story = { + render: (args) => ({ + props: args, + template: /* HTML */ ` + + + + `, + }), +}; + +export const PoppedOut: Story = { + render: (args) => ({ + props: args, + template: /* HTML */ ` +
+ +
+ `, + }), +}; diff --git a/apps/browser/src/platform/popup/layout/popup-page.component.html b/apps/browser/src/platform/popup/layout/popup-page.component.html new file mode 100644 index 0000000000..ba871d6319 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-page.component.html @@ -0,0 +1,7 @@ + +
+
+ +
+
+ diff --git a/apps/browser/src/platform/popup/layout/popup-page.component.ts b/apps/browser/src/platform/popup/layout/popup-page.component.ts new file mode 100644 index 0000000000..1223a6f418 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-page.component.ts @@ -0,0 +1,11 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "popup-page", + templateUrl: "popup-page.component.html", + standalone: true, + host: { + class: "tw-h-full tw-flex tw-flex-col tw-flex-1 tw-overflow-y-auto", + }, +}) +export class PopupPageComponent {} diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html new file mode 100644 index 0000000000..a0ff252c6c --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html @@ -0,0 +1,32 @@ +
+ +
+ diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts new file mode 100644 index 0000000000..3a275454d9 --- /dev/null +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts @@ -0,0 +1,43 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; + +import { LinkModule } from "@bitwarden/components"; + +@Component({ + selector: "popup-tab-navigation", + templateUrl: "popup-tab-navigation.component.html", + standalone: true, + imports: [CommonModule, LinkModule, RouterModule], + host: { + class: "tw-block tw-h-full tw-w-full tw-flex tw-flex-col", + }, +}) +export class PopupTabNavigationComponent { + navButtons = [ + { + label: "Vault", + page: "/vault", + iconKey: "lock", + iconKeyActive: "lock-f", + }, + { + label: "Generator", + page: "/generator", + iconKey: "generate", + iconKeyActive: "generate-f", + }, + { + label: "Send", + page: "/send", + iconKey: "send", + iconKeyActive: "send-f", + }, + { + label: "Settings", + page: "/settings", + iconKey: "cog", + iconKeyActive: "cog-f", + }, + ]; +} diff --git a/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts b/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts index 64935ab591..259d6f154a 100644 --- a/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts +++ b/apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts @@ -78,6 +78,11 @@ export default abstract class AbstractChromeStorageService async save(key: string, obj: any): Promise { obj = objToStore(obj); + if (obj == null) { + // Safari does not support set of null values + return this.remove(key); + } + const keyedObj = { [key]: obj }; return new Promise((resolve) => { this.chromeStorageApi.set(keyedObj, () => { diff --git a/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts b/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts index 812901879d..ceadc16a58 100644 --- a/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts +++ b/apps/browser/src/platform/services/abstractions/chrome-storage-api.service.spec.ts @@ -62,6 +62,17 @@ describe("ChromeStorageApiService", () => { expect.any(Function), ); }); + + it("removes the key when the value is null", async () => { + const removeMock = chrome.storage.local.remove as jest.Mock; + removeMock.mockImplementation((key, callback) => { + delete store[key]; + callback(); + }); + const key = "key"; + await service.save(key, null); + expect(removeMock).toHaveBeenCalledWith(key, expect.any(Function)); + }); }); describe("get", () => { diff --git a/apps/browser/src/platform/services/browser-crypto.service.ts b/apps/browser/src/platform/services/browser-crypto.service.ts index d7533a22d6..cd23c916c6 100644 --- a/apps/browser/src/platform/services/browser-crypto.service.ts +++ b/apps/browser/src/platform/services/browser-crypto.service.ts @@ -1,6 +1,7 @@ import { firstValueFrom } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -28,6 +29,7 @@ export class BrowserCryptoService extends CryptoService { accountService: AccountService, stateProvider: StateProvider, private biometricStateService: BiometricStateService, + kdfConfigService: KdfConfigService, ) { super( masterPasswordService, @@ -39,6 +41,7 @@ export class BrowserCryptoService extends CryptoService { stateService, accountService, stateProvider, + kdfConfigService, ); } override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: UserId): Promise { diff --git a/apps/browser/src/platform/services/browser-state.service.spec.ts b/apps/browser/src/platform/services/browser-state.service.spec.ts index 8f43998321..f06126dcf5 100644 --- a/apps/browser/src/platform/services/browser-state.service.spec.ts +++ b/apps/browser/src/platform/services/browser-state.service.spec.ts @@ -27,7 +27,6 @@ describe("Browser State Service", () => { let diskStorageService: MockProxy; let logService: MockProxy; let stateFactory: MockProxy>; - let useAccountCache: boolean; let environmentService: MockProxy; let tokenService: MockProxy; let migrationRunner: MockProxy; @@ -46,8 +45,6 @@ describe("Browser State Service", () => { environmentService = mock(); tokenService = mock(); migrationRunner = mock(); - // turn off account cache for tests - useAccountCache = false; state = new State(new GlobalState()); state.accounts[userId] = new Account({ @@ -78,7 +75,6 @@ describe("Browser State Service", () => { environmentService, tokenService, migrationRunner, - useAccountCache, ); }); diff --git a/apps/browser/src/platform/services/default-browser-state.service.ts b/apps/browser/src/platform/services/default-browser-state.service.ts index f1f306dbc0..b9cd219076 100644 --- a/apps/browser/src/platform/services/default-browser-state.service.ts +++ b/apps/browser/src/platform/services/default-browser-state.service.ts @@ -15,7 +15,6 @@ import { MigrationRunner } from "@bitwarden/common/platform/services/migration-r import { StateService as BaseStateService } from "@bitwarden/common/platform/services/state.service"; import { Account } from "../../models/account"; -import { BrowserApi } from "../browser/browser-api"; import { browserSession, sessionSync } from "../decorators/session-sync-observable"; import { BrowserStateService } from "./abstractions/browser-state.service"; @@ -45,7 +44,6 @@ export class DefaultBrowserStateService environmentService: EnvironmentService, tokenService: TokenService, migrationRunner: MigrationRunner, - useAccountCache = true, ) { super( storageService, @@ -57,45 +55,7 @@ export class DefaultBrowserStateService environmentService, tokenService, migrationRunner, - useAccountCache, ); - - // TODO: This is a hack to fix having a disk cache on both the popup and - // the background page that can get out of sync. We need to work out the - // best way to handle caching with multiple instances of the state service. - if (useAccountCache) { - BrowserApi.storageChangeListener((changes, namespace) => { - if (namespace === "local") { - for (const key of Object.keys(changes)) { - if (key !== "accountActivity" && this.accountDiskCache.value[key]) { - this.deleteDiskCache(key); - } - } - } - }); - - BrowserApi.addListener( - chrome.runtime.onMessage, - (message: { command: string }, _, respond) => { - if (message.command === "initializeDiskCache") { - respond(JSON.stringify(this.accountDiskCache.value)); - } - }, - ); - } - } - - override async initAccountState(): Promise { - if (this.isRecoveredSession && this.useAccountCache) { - // request cache initialization - - const response = await BrowserApi.sendMessageWithResponse("initializeDiskCache"); - this.accountDiskCache.next(JSON.parse(response)); - - return; - } - - await super.initAccountState(); } async addAccount(account: Account) { diff --git a/apps/browser/src/platform/services/local-backed-session-storage.service.ts b/apps/browser/src/platform/services/local-backed-session-storage.service.ts index 5432e8d918..0fa359181d 100644 --- a/apps/browser/src/platform/services/local-backed-session-storage.service.ts +++ b/apps/browser/src/platform/services/local-backed-session-storage.service.ts @@ -92,9 +92,16 @@ export class LocalBackedSessionStorageService // This is for observation purposes only. At some point, we don't want to write to local session storage if the value is the same. if (this.platformUtilsService.isDev()) { const existingValue = this.cache[key] as T; - if (this.compareValues(existingValue, obj)) { - this.logService.warning(`Possible unnecessary write to local session storage. Key: ${key}`); - this.logService.warning(obj as any); + try { + if (this.compareValues(existingValue, obj)) { + this.logService.warning( + `Possible unnecessary write to local session storage. Key: ${key}`, + ); + this.logService.warning(obj as any); + } + } catch (err) { + this.logService.warning(`Error while comparing values for key: ${key}`); + this.logService.warning(err); } } diff --git a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts index e9f7f17d9b..6e3b3aa403 100644 --- a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts +++ b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts @@ -175,11 +175,13 @@ export abstract class BrowserPlatformUtilsService implements PlatformUtilsServic } getApplicationVersion(): Promise { - return Promise.resolve(BrowserApi.getApplicationVersion()); + const manifest = chrome.runtime.getManifest(); + return Promise.resolve(manifest.version_name ?? manifest.version); } - async getApplicationVersionNumber(): Promise { - return (await this.getApplicationVersion()).split(RegExp("[+|-]"))[0].trim(); + getApplicationVersionNumber(): Promise { + const manifest = chrome.runtime.getManifest(); + return Promise.resolve(manifest.version.split(RegExp("[+|-]"))[0].trim()); } supportsWebAuthn(win: Window): boolean { diff --git a/apps/browser/src/platform/state/background-derived-state.provider.ts b/apps/browser/src/platform/state/background-derived-state.provider.ts index f3d217789e..cbc5a34b37 100644 --- a/apps/browser/src/platform/state/background-derived-state.provider.ts +++ b/apps/browser/src/platform/state/background-derived-state.provider.ts @@ -1,9 +1,5 @@ import { Observable } from "rxjs"; -import { - AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; import { DeriveDefinition, DerivedState } from "@bitwarden/common/platform/state"; // eslint-disable-next-line import/no-restricted-paths -- extending this class for this client import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider"; @@ -16,14 +12,11 @@ export class BackgroundDerivedStateProvider extends DefaultDerivedStateProvider parentState$: Observable, deriveDefinition: DeriveDefinition, dependencies: TDeps, - storageLocation: [string, AbstractStorageService & ObservableStorageService], ): DerivedState { - const [cacheKey, storageService] = storageLocation; return new BackgroundDerivedState( parentState$, deriveDefinition, - storageService, - cacheKey, + deriveDefinition.buildCacheKey(), dependencies, ); } diff --git a/apps/browser/src/platform/state/background-derived-state.ts b/apps/browser/src/platform/state/background-derived-state.ts index c62795acdc..61768cb970 100644 --- a/apps/browser/src/platform/state/background-derived-state.ts +++ b/apps/browser/src/platform/state/background-derived-state.ts @@ -1,10 +1,7 @@ -import { Observable, Subscription } from "rxjs"; +import { Observable, Subscription, concatMap } from "rxjs"; import { Jsonify } from "type-fest"; -import { - AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { DeriveDefinition } from "@bitwarden/common/platform/state"; // eslint-disable-next-line import/no-restricted-paths -- extending this class for this client import { DefaultDerivedState } from "@bitwarden/common/platform/state/implementations/default-derived-state"; @@ -22,11 +19,10 @@ export class BackgroundDerivedState< constructor( parentState$: Observable, deriveDefinition: DeriveDefinition, - memoryStorage: AbstractStorageService & ObservableStorageService, portName: string, dependencies: TDeps, ) { - super(parentState$, deriveDefinition, memoryStorage, dependencies); + super(parentState$, deriveDefinition, dependencies); // listen for foreground derived states to connect BrowserApi.addListener(chrome.runtime.onConnect, (port) => { @@ -42,7 +38,20 @@ export class BackgroundDerivedState< }); port.onMessage.addListener(listenerCallback); - const stateSubscription = this.state$.subscribe(); + const stateSubscription = this.state$ + .pipe( + concatMap(async (state) => { + await this.sendMessage( + { + action: "nextState", + data: JSON.stringify(state), + id: Utils.newGuid(), + }, + port, + ); + }), + ) + .subscribe(); this.portSubscriptions.set(port, stateSubscription); }); diff --git a/apps/browser/src/platform/state/derived-state-interactions.spec.ts b/apps/browser/src/platform/state/derived-state-interactions.spec.ts index a5df01bc98..823c071a4c 100644 --- a/apps/browser/src/platform/state/derived-state-interactions.spec.ts +++ b/apps/browser/src/platform/state/derived-state-interactions.spec.ts @@ -4,14 +4,13 @@ */ import { NgZone } from "@angular/core"; -import { FakeStorageService } from "@bitwarden/common/../spec/fake-storage.service"; -import { awaitAsync, trackEmissions } from "@bitwarden/common/../spec/utils"; import { mock } from "jest-mock-extended"; import { Subject, firstValueFrom } from "rxjs"; import { DeriveDefinition } from "@bitwarden/common/platform/state"; // eslint-disable-next-line import/no-restricted-paths -- needed to define a derive definition import { StateDefinition } from "@bitwarden/common/platform/state/state-definition"; +import { awaitAsync, trackEmissions, ObservableTracker } from "@bitwarden/common/spec"; import { mockPorts } from "../../../spec/mock-port.spec-util"; @@ -22,6 +21,7 @@ const stateDefinition = new StateDefinition("test", "memory"); const deriveDefinition = new DeriveDefinition(stateDefinition, "test", { derive: (dateString: string) => (dateString == null ? null : new Date(dateString)), deserializer: (dateString: string) => (dateString == null ? null : new Date(dateString)), + cleanupDelayMs: 1000, }); // Mock out the runInsideAngular operator so we don't have to deal with zone.js @@ -35,7 +35,6 @@ describe("foreground background derived state interactions", () => { let foreground: ForegroundDerivedState; let background: BackgroundDerivedState>; let parentState$: Subject; - let memoryStorage: FakeStorageService; const initialParent = "2020-01-01"; const ngZone = mock(); const portName = "testPort"; @@ -43,16 +42,9 @@ describe("foreground background derived state interactions", () => { beforeEach(() => { mockPorts(); parentState$ = new Subject(); - memoryStorage = new FakeStorageService(); - background = new BackgroundDerivedState( - parentState$, - deriveDefinition, - memoryStorage, - portName, - {}, - ); - foreground = new ForegroundDerivedState(deriveDefinition, memoryStorage, portName, ngZone); + background = new BackgroundDerivedState(parentState$, deriveDefinition, portName, {}); + foreground = new ForegroundDerivedState(deriveDefinition, portName, ngZone); }); afterEach(() => { @@ -72,21 +64,13 @@ describe("foreground background derived state interactions", () => { }); it("should initialize a late-connected foreground", async () => { - const newForeground = new ForegroundDerivedState( - deriveDefinition, - memoryStorage, - portName, - ngZone, - ); - const backgroundEmissions = trackEmissions(background.state$); + const newForeground = new ForegroundDerivedState(deriveDefinition, portName, ngZone); + const backgroundTracker = new ObservableTracker(background.state$); parentState$.next(initialParent); - await awaitAsync(); + const foregroundTracker = new ObservableTracker(newForeground.state$); - const foregroundEmissions = trackEmissions(newForeground.state$); - await awaitAsync(10); - - expect(backgroundEmissions).toEqual([new Date(initialParent)]); - expect(foregroundEmissions).toEqual([new Date(initialParent)]); + expect(await backgroundTracker.expectEmission()).toEqual(new Date(initialParent)); + expect(await foregroundTracker.expectEmission()).toEqual(new Date(initialParent)); }); describe("forceValue", () => { diff --git a/apps/browser/src/platform/state/foreground-derived-state.provider.ts b/apps/browser/src/platform/state/foreground-derived-state.provider.ts index d9262e3b6e..8b8d82b914 100644 --- a/apps/browser/src/platform/state/foreground-derived-state.provider.ts +++ b/apps/browser/src/platform/state/foreground-derived-state.provider.ts @@ -1,11 +1,6 @@ import { NgZone } from "@angular/core"; import { Observable } from "rxjs"; -import { - AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { DeriveDefinition, DerivedState } from "@bitwarden/common/platform/state"; // eslint-disable-next-line import/no-restricted-paths -- extending this class for this client import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider"; @@ -14,19 +9,18 @@ import { DerivedStateDependencies } from "@bitwarden/common/src/types/state"; import { ForegroundDerivedState } from "./foreground-derived-state"; export class ForegroundDerivedStateProvider extends DefaultDerivedStateProvider { - constructor( - storageServiceProvider: StorageServiceProvider, - private ngZone: NgZone, - ) { - super(storageServiceProvider); + constructor(private ngZone: NgZone) { + super(); } override buildDerivedState( _parentState$: Observable, deriveDefinition: DeriveDefinition, _dependencies: TDeps, - storageLocation: [string, AbstractStorageService & ObservableStorageService], ): DerivedState { - const [cacheKey, storageService] = storageLocation; - return new ForegroundDerivedState(deriveDefinition, storageService, cacheKey, this.ngZone); + return new ForegroundDerivedState( + deriveDefinition, + deriveDefinition.buildCacheKey(), + this.ngZone, + ); } } diff --git a/apps/browser/src/platform/state/foreground-derived-state.spec.ts b/apps/browser/src/platform/state/foreground-derived-state.spec.ts index 2c29f39bc1..ee224540c1 100644 --- a/apps/browser/src/platform/state/foreground-derived-state.spec.ts +++ b/apps/browser/src/platform/state/foreground-derived-state.spec.ts @@ -1,11 +1,5 @@ -/** - * need to update test environment so structuredClone works appropriately - * @jest-environment ../../libs/shared/test.environment.ts - */ - import { NgZone } from "@angular/core"; -import { awaitAsync, trackEmissions } from "@bitwarden/common/../spec"; -import { FakeStorageService } from "@bitwarden/common/../spec/fake-storage.service"; +import { awaitAsync } from "@bitwarden/common/../spec"; import { mock } from "jest-mock-extended"; import { DeriveDefinition } from "@bitwarden/common/platform/state"; @@ -32,15 +26,12 @@ jest.mock("../browser/run-inside-angular.operator", () => { describe("ForegroundDerivedState", () => { let sut: ForegroundDerivedState; - let memoryStorage: FakeStorageService; const portName = "testPort"; const ngZone = mock(); beforeEach(() => { - memoryStorage = new FakeStorageService(); - memoryStorage.internalUpdateValuesRequireDeserialization(true); mockPorts(); - sut = new ForegroundDerivedState(deriveDefinition, memoryStorage, portName, ngZone); + sut = new ForegroundDerivedState(deriveDefinition, portName, ngZone); }); afterEach(() => { @@ -67,18 +58,4 @@ describe("ForegroundDerivedState", () => { expect(disconnectSpy).toHaveBeenCalled(); expect(sut["port"]).toBeNull(); }); - - it("should emit when the memory storage updates", async () => { - const dateString = "2020-01-01"; - const emissions = trackEmissions(sut.state$); - - await memoryStorage.save(deriveDefinition.storageKey, { - derived: true, - value: new Date(dateString), - }); - - await awaitAsync(); - - expect(emissions).toEqual([new Date(dateString)]); - }); }); diff --git a/apps/browser/src/platform/state/foreground-derived-state.ts b/apps/browser/src/platform/state/foreground-derived-state.ts index b9dda763df..6abe363876 100644 --- a/apps/browser/src/platform/state/foreground-derived-state.ts +++ b/apps/browser/src/platform/state/foreground-derived-state.ts @@ -6,19 +6,14 @@ import { filter, firstValueFrom, map, - merge, of, share, switchMap, tap, timer, } from "rxjs"; -import { Jsonify, JsonObject } from "type-fest"; +import { Jsonify } from "type-fest"; -import { - AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { DeriveDefinition, DerivedState } from "@bitwarden/common/platform/state"; import { DerivedStateDependencies } from "@bitwarden/common/types/state"; @@ -27,41 +22,28 @@ import { fromChromeEvent } from "../browser/from-chrome-event"; import { runInsideAngular } from "../browser/run-inside-angular.operator"; export class ForegroundDerivedState implements DerivedState { - private storageKey: string; private port: chrome.runtime.Port; private backgroundResponses$: Observable; state$: Observable; constructor( private deriveDefinition: DeriveDefinition, - private memoryStorage: AbstractStorageService & ObservableStorageService, private portName: string, private ngZone: NgZone, ) { - this.storageKey = deriveDefinition.storageKey; - - const initialStorageGet$ = defer(() => { - return this.getStoredValue(); - }).pipe( - filter((s) => s.derived), - map((s) => s.value), - ); - - const latestStorage$ = this.memoryStorage.updates$.pipe( - filter((s) => s.key === this.storageKey), - switchMap(async (storageUpdate) => { - if (storageUpdate.updateType === "remove") { - return null; - } - - return await this.getStoredValue(); - }), - filter((s) => s.derived), - map((s) => s.value), - ); + const latestValueFromPort$ = (port: chrome.runtime.Port) => { + return fromChromeEvent(port.onMessage).pipe( + map(([message]) => message as DerivedStateMessage), + filter((message) => message.originator === "background" && message.action === "nextState"), + map((message) => { + const json = JSON.parse(message.data) as Jsonify; + return this.deriveDefinition.deserialize(json); + }), + ); + }; this.state$ = defer(() => of(this.initializePort())).pipe( - switchMap(() => merge(initialStorageGet$, latestStorage$)), + switchMap(() => latestValueFromPort$(this.port)), share({ connector: () => new ReplaySubject(1), resetOnRefCountZero: () => @@ -130,28 +112,4 @@ export class ForegroundDerivedState implements DerivedState { this.port = null; this.backgroundResponses$ = null; } - - protected async getStoredValue(): Promise<{ derived: boolean; value: TTo | null }> { - if (this.memoryStorage.valuesRequireDeserialization) { - const storedJson = await this.memoryStorage.get< - Jsonify<{ derived: true; value: JsonObject }> - >(this.storageKey); - - if (!storedJson?.derived) { - return { derived: false, value: null }; - } - - const value = this.deriveDefinition.deserialize(storedJson.value as any); - - return { derived: true, value }; - } else { - const stored = await this.memoryStorage.get<{ derived: true; value: TTo }>(this.storageKey); - - if (!stored?.derived) { - return { derived: false, value: null }; - } - - return { derived: true, value: stored.value }; - } - } } diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 5718542b01..2fb582d693 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -36,6 +36,10 @@ import { TwoFactorComponent } from "../auth/popup/two-factor.component"; import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.component"; import { AutofillComponent } from "../autofill/popup/settings/autofill.component"; import { HeaderComponent } from "../platform/popup/header.component"; +import { PopupFooterComponent } from "../platform/popup/layout/popup-footer.component"; +import { PopupHeaderComponent } from "../platform/popup/layout/popup-header.component"; +import { PopupPageComponent } from "../platform/popup/layout/popup-page.component"; +import { PopupTabNavigationComponent } from "../platform/popup/layout/popup-tab-navigation.component"; import { FilePopoutCalloutComponent } from "../tools/popup/components/file-popout-callout.component"; import { GeneratorComponent } from "../tools/popup/generator/generator.component"; import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component"; @@ -108,6 +112,10 @@ import "../platform/popup/locales"; AccountComponent, ButtonModule, ExportScopeCalloutComponent, + PopupPageComponent, + PopupTabNavigationComponent, + PopupFooterComponent, + PopupHeaderComponent, ], declarations: [ ActionButtonsComponent, diff --git a/apps/browser/src/popup/scss/base.scss b/apps/browser/src/popup/scss/base.scss index 73da455941..80c7536087 100644 --- a/apps/browser/src/popup/scss/base.scss +++ b/apps/browser/src/popup/scss/base.scss @@ -68,7 +68,7 @@ img { border: none; } -a { +a:not(popup-page a, popup-tab-navigation a) { text-decoration: none; @include themify($themes) { @@ -171,7 +171,7 @@ cdk-virtual-scroll-viewport::-webkit-scrollbar-thumb, } } -header:not(bit-callout header, bit-dialog header) { +header:not(bit-callout header, bit-dialog header, popup-page header) { height: 44px; display: flex; @@ -448,7 +448,7 @@ app-root { } } -main { +main:not(popup-page main) { position: absolute; top: 44px; bottom: 0; diff --git a/apps/browser/src/popup/services/init.service.ts b/apps/browser/src/popup/services/init.service.ts index c9e6d66c2a..63ce45c9b7 100644 --- a/apps/browser/src/popup/services/init.service.ts +++ b/apps/browser/src/popup/services/init.service.ts @@ -2,6 +2,7 @@ import { DOCUMENT } from "@angular/common"; import { Inject, Injectable } from "@angular/core"; import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -15,6 +16,7 @@ export class InitService { private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, private stateService: StateServiceAbstraction, + private twoFactorService: TwoFactorService, private logService: LogServiceAbstraction, private themingService: AbstractThemingService, @Inject(DOCUMENT) private document: Document, @@ -22,8 +24,9 @@ export class InitService { init() { return async () => { - await this.stateService.init(); + await this.stateService.init({ runMigrations: false }); // Browser background is responsible for migrations await this.i18nService.init(); + this.twoFactorService.init(); if (!BrowserPopupUtils.inPopup(window)) { window.document.body.classList.add("body-full"); diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 47d02b5cfa..a7d631824c 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -13,12 +13,10 @@ import { SYSTEM_THEME_OBSERVABLE, SafeInjectionToken, INTRAPROCESS_MESSAGING_SUBJECT, + CLIENT_TYPE, } from "@bitwarden/angular/services/injection-tokens"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; -import { - AuthRequestServiceAbstraction, - LoginStrategyServiceAbstraction, -} from "@bitwarden/auth/common"; +import { AuthRequestServiceAbstraction } from "@bitwarden/auth/common"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; @@ -28,12 +26,11 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; -import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { @@ -49,6 +46,7 @@ import { UserNotificationSettingsServiceAbstraction, } from "@bitwarden/common/autofill/services/user-notification-settings.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { ClientType } from "@bitwarden/common/enums"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -170,21 +168,11 @@ const safeProviders: SafeProvider[] = [ useClass: UnauthGuardService, deps: [AuthServiceAbstraction, Router], }), - safeProvider({ - provide: TwoFactorService, - useFactory: getBgService("twoFactorService"), - deps: [], - }), safeProvider({ provide: AuthServiceAbstraction, useFactory: getBgService("authService"), deps: [], }), - safeProvider({ - provide: LoginStrategyServiceAbstraction, - useFactory: getBgService("loginStrategyService"), - deps: [], - }), safeProvider({ provide: SsoLoginServiceAbstraction, useFactory: getBgService("ssoLoginService"), @@ -252,8 +240,8 @@ const safeProviders: SafeProvider[] = [ deps: [], }), safeProvider({ - provide: DeviceTrustCryptoServiceAbstraction, - useFactory: getBgService("deviceTrustCryptoService"), + provide: DeviceTrustServiceAbstraction, + useFactory: getBgService("deviceTrustService"), deps: [], }), safeProvider({ @@ -423,7 +411,7 @@ const safeProviders: SafeProvider[] = [ logService: LogService, accountService: AccountServiceAbstraction, environmentService: EnvironmentService, - tokenService: TokenServiceAbstraction, + tokenService: TokenService, migrationRunner: MigrationRunner, ) => { return new DefaultBrowserStateService( @@ -445,7 +433,7 @@ const safeProviders: SafeProvider[] = [ LogService, AccountServiceAbstraction, EnvironmentService, - TokenServiceAbstraction, + TokenService, MigrationRunner, ], }), @@ -489,7 +477,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: DerivedStateProvider, useClass: ForegroundDerivedStateProvider, - deps: [StorageServiceProvider, NgZone], + deps: [NgZone], }), safeProvider({ provide: AutofillSettingsServiceAbstraction, @@ -574,6 +562,10 @@ const safeProviders: SafeProvider[] = [ OBSERVABLE_LARGE_OBJECT_MEMORY_STORAGE, ], }), + safeProvider({ + provide: CLIENT_TYPE, + useValue: ClientType.Browser, + }), safeProvider({ provide: TaskSchedulerService, useExisting: BrowserTaskSchedulerService, diff --git a/apps/browser/src/popup/settings/about.component.html b/apps/browser/src/popup/settings/about.component.html index a4ad0ba801..e68a664ba7 100644 --- a/apps/browser/src/popup/settings/about.component.html +++ b/apps/browser/src/popup/settings/about.component.html @@ -5,7 +5,7 @@
Bitwarden

© Bitwarden Inc. 2015-{{ year }}

-

{{ "version" | i18n }}: {{ version }}

+

{{ "version" | i18n }}: {{ version$ | async }}

{{ "serverVersion" | i18n }}: {{ data.serverConfig?.version }} diff --git a/apps/browser/src/popup/settings/about.component.ts b/apps/browser/src/popup/settings/about.component.ts index 61b5749b51..d7f98c1e7f 100644 --- a/apps/browser/src/popup/settings/about.component.ts +++ b/apps/browser/src/popup/settings/about.component.ts @@ -1,14 +1,13 @@ import { CommonModule } from "@angular/common"; import { Component } from "@angular/core"; -import { combineLatest, map } from "rxjs"; +import { Observable, combineLatest, defer, map } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { ButtonModule, DialogModule } from "@bitwarden/components"; -import { BrowserApi } from "../../platform/browser/browser-api"; - @Component({ templateUrl: "about.component.html", standalone: true, @@ -16,7 +15,7 @@ import { BrowserApi } from "../../platform/browser/browser-api"; }) export class AboutComponent { protected year = new Date().getFullYear(); - protected version = BrowserApi.getApplicationVersion(); + protected version$: Observable; protected data$ = combineLatest([ this.configService.serverConfig$, @@ -26,5 +25,8 @@ export class AboutComponent { constructor( private configService: ConfigService, private environmentService: EnvironmentService, - ) {} + private platformUtilsService: PlatformUtilsService, + ) { + this.version$ = defer(() => this.platformUtilsService.getApplicationVersion()); + } } diff --git a/apps/browser/src/popup/settings/settings.component.ts b/apps/browser/src/popup/settings/settings.component.ts index fa6c64fcc5..c7e5b7dc95 100644 --- a/apps/browser/src/popup/settings/settings.component.ts +++ b/apps/browser/src/popup/settings/settings.component.ts @@ -21,6 +21,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaul import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { DeviceType } from "@bitwarden/common/enums"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; @@ -86,6 +87,7 @@ export class SettingsComponent implements OnInit { private destroy$ = new Subject(); constructor( + private accountService: AccountService, private policyService: PolicyService, private formBuilder: FormBuilder, private platformUtilsService: PlatformUtilsService, @@ -434,8 +436,9 @@ export class SettingsComponent implements OnInit { type: "info", }); + const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; if (confirmed) { - this.messagingService.send("logout"); + this.messagingService.send("logout", { userId: userId }); } } diff --git a/apps/browser/src/tools/background/fileless-importer.background.ts b/apps/browser/src/tools/background/fileless-importer.background.ts index 07c6408e8d..fed5541f52 100644 --- a/apps/browser/src/tools/background/fileless-importer.background.ts +++ b/apps/browser/src/tools/background/fileless-importer.background.ts @@ -183,7 +183,7 @@ class FilelessImporterBackground implements FilelessImporterBackgroundInterface return; } - const filelessImportFeatureFlagEnabled = await this.configService.getFeatureFlag( + const filelessImportFeatureFlagEnabled = await this.configService.getFeatureFlag( FeatureFlag.BrowserFilelessImport, ); const userAuthStatus = await this.authService.getAuthStatus(); diff --git a/apps/browser/src/tools/popup/services/browser-send-state.service.ts b/apps/browser/src/tools/popup/services/browser-send-state.service.ts index 52aeb01a92..11e71c9b20 100644 --- a/apps/browser/src/tools/popup/services/browser-send-state.service.ts +++ b/apps/browser/src/tools/popup/services/browser-send-state.service.ts @@ -46,7 +46,9 @@ export class BrowserSendStateService { * the send component on the browser */ async setBrowserSendComponentState(value: BrowserSendComponentState): Promise { - await this.activeUserBrowserSendComponentState.update(() => value); + await this.activeUserBrowserSendComponentState.update(() => value, { + shouldUpdate: (current) => !(current == null && value == null), + }); } /** Get the active user's browser component state @@ -60,6 +62,8 @@ export class BrowserSendStateService { * @param { BrowserComponentState } value set the scroll position and search text for the send component on the browser */ async setBrowserSendTypeComponentState(value: BrowserComponentState): Promise { - await this.activeUserBrowserSendTypeComponentState.update(() => value); + await this.activeUserBrowserSendTypeComponentState.update(() => value, { + shouldUpdate: (current) => !(current == null && value == null), + }); } } diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts index 4d2674fd70..d882dfd525 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts @@ -292,6 +292,8 @@ export class CurrentTabComponent implements OnInit, OnDestroy { const ciphers = await this.cipherService.getAllDecryptedForUrl( this.url, otherTypes.length > 0 ? otherTypes : null, + null, + false, ); this.loginCiphers = []; diff --git a/apps/browser/src/vault/services/vault-browser-state.service.ts b/apps/browser/src/vault/services/vault-browser-state.service.ts index a0d55a9d55..43a28928da 100644 --- a/apps/browser/src/vault/services/vault-browser-state.service.ts +++ b/apps/browser/src/vault/services/vault-browser-state.service.ts @@ -52,7 +52,9 @@ export class VaultBrowserStateService { } async setBrowserGroupingsComponentState(value: BrowserGroupingsComponentState): Promise { - await this.activeUserVaultBrowserGroupingsComponentState.update(() => value); + await this.activeUserVaultBrowserGroupingsComponentState.update(() => value, { + shouldUpdate: (current) => !(current == null && value == null), + }); } async getBrowserVaultItemsComponentState(): Promise { @@ -60,6 +62,8 @@ export class VaultBrowserStateService { } async setBrowserVaultItemsComponentState(value: BrowserComponentState): Promise { - await this.activeUserVaultBrowserComponentState.update(() => value); + await this.activeUserVaultBrowserComponentState.update(() => value, { + shouldUpdate: (current) => !(current == null && value == null), + }); } } diff --git a/apps/browser/store/locales/de/copy.resx b/apps/browser/store/locales/de/copy.resx index 2267c6c85e..eb3ab2afd4 100644 --- a/apps/browser/store/locales/de/copy.resx +++ b/apps/browser/store/locales/de/copy.resx @@ -121,55 +121,55 @@ Bitwarden Passwort-Manager - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + Zu Hause, am Arbeitsplatz oder unterwegs schützt Bitwarden einfach alle deine Passwörter, Passkeys und vertraulichen Informationen. - Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! + Ausgezeichnet als bester Passwortmanager von PCMag, WIRED, The Verge, CNET, G2 und vielen anderen! -SECURE YOUR DIGITAL LIFE -Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. +SCHÜTZE DEIN DIGITALES LEBEN +Sicher dein digitales Leben und schütze dich vor Passwortdiebstählen, indem du individuelle, sichere Passwörter für jedes Konto erstellest und speicherst. Verwalte alles in einem Ende-zu-Ende verschlüsselten Passwort-Tresor, auf den nur du Zugriff hast. -ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE -Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. +ZUGRIFF AUF DEINE DATEN, ÜBERALL, JEDERZEIT UND AUF JEDEM GERÄT +Verwalte, speichere, sichere und teile einfach eine unbegrenzte Anzahl von Passwörtern auf einer unbegrenzten Anzahl von Geräten ohne Einschränkungen. -EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE -Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. +JEDER SOLLTE DIE MÖGLICHKEIT HABEN, ONLINE GESCHÜTZT ZU BLEIBEN +Verwende Bitwarden kostenlos, ohne Werbung oder Datenverkauf. Bitwarden glaubt, dass jeder die Möglichkeit haben sollte, online geschützt zu bleiben. Premium-Abos bieten Zugang zu erweiterten Funktionen. -EMPOWER YOUR TEAMS WITH BITWARDEN -Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. +STÄRKE DEINE TEAMS MIT BITWARDEN +Tarife für Teams und Enterprise enthalten professionelle Business-Funktionen. Einige Beispiele sind SSO-Integration, Selbst-Hosting, Directory-Integration und SCIM-Bereitstellung, globale Richtlinien, API-Zugang, Ereignisprotokolle und mehr. -Use Bitwarden to secure your workforce and share sensitive information with colleagues. +Nutze Bitwarden, um deine Mitarbeiter abzusichern und sensible Informationen mit Kollegen zu teilen. -More reasons to choose Bitwarden: +Weitere Gründe, Bitwarden zu wählen: -World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Weltklasse-Verschlüsselung +Passwörter werden mit fortschrittlicher Ende-zu-Ende-Verschlüsselung (AES-256 bit, salted hashtag und PBKDF2 SHA-256) geschützt, damit deine Daten sicher und geheim bleiben. -3rd-party Audits -Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. +3rd-Party-Prüfungen +Bitwarden führt regelmäßig umfassende Sicherheitsprüfungen durch Dritte von namhaften Sicherheitsfirmen durch. Diese jährlichen Prüfungen umfassen Quellcode-Bewertungen und Penetration-Tests für Bitwarden-IPs, Server und Webanwendungen. -Advanced 2FA -Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. +Erweiterte 2FA +Schütze deine Zugangsdaten mit einem Authentifikator eines Drittanbieters, per E-Mail verschickten Codes oder FIDO2 WebAuthn-Zugangsadaten wie einem Hardware-Sicherheitsschlüssel oder Passkey. Bitwarden Send -Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. +Übertrage Daten direkt an andere, während die Ende-zu-Ende-Verschlüsselung beibehalten wird und die Verbreitung begrenzt werden kann. -Built-in Generator -Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. +Eingebauter Generator +Erstelle lange, komplexe und eindeutige Passwörter und eindeutige Benutzernamen für jede Website, die du besuchst. Integriere E-Mail-Alias-Anbieter für zusätzlichen Datenschutz. -Global Translations -Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. +Globale Übersetzungen +Es gibt Bitwarden-Übersetzungen für mehr als 60 Sprachen, die von der weltweiten Community über Crowdin übersetzt werden. -Cross-Platform Applications -Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. +Plattformübergreifende Anwendungen +Schütze und teile sensible Daten in deinem Bitwarden Tresor von jedem Browser, mobilen Gerät oder Desktop-Betriebssystem und mehr. -Bitwarden secures more than just passwords -End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! +Bitwarden schützt mehr als nur Passwörter +Ende-zu-Ende verschlüsselte Zugangsverwaltungs-Lösungen von Bitwarden ermöglicht es Organisationen, alles zu sichern, einschließlich Entwicklergeheimnissen und Passkeys. Besuche Bitwarden.com, um mehr über den Bitwarden Secrets Manager und Bitwarden Passwordless.dev zu erfahren! - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + Zu Hause, am Arbeitsplatz oder unterwegs schützt Bitwarden einfach alle deine Passwörter, Passkeys und vertraulichen Informationen. Synchronisiere und greife auf deinen Tresor von unterschiedlichen Geräten aus zu diff --git a/apps/browser/store/locales/ko/copy.resx b/apps/browser/store/locales/ko/copy.resx index fdfb93ad6a..595663b1ca 100644 --- a/apps/browser/store/locales/ko/copy.resx +++ b/apps/browser/store/locales/ko/copy.resx @@ -121,7 +121,7 @@ Bitwarden Password Manager - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + 집에서도, 직장에서도, 이동 중에도 Bitwarden은 비밀번호, 패스키, 민감 정보를 쉽게 보호합니다. Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! @@ -169,7 +169,7 @@ End-to-end encrypted credential management solutions from Bitwarden empower orga - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + 집에서도, 직장에서도, 이동 중에도 Bitwarden은 비밀번호, 패스키, 민감 정보를 쉽게 보호합니다. 여러 기기에서 보관함에 접근하고 동기화할 수 있습니다. diff --git a/apps/browser/store/locales/pl/copy.resx b/apps/browser/store/locales/pl/copy.resx index 60709c7d4d..5641c68c48 100644 --- a/apps/browser/store/locales/pl/copy.resx +++ b/apps/browser/store/locales/pl/copy.resx @@ -118,58 +118,58 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Bitwarden Password Manager + Menedżer Haseł Bitwarden - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + W domu, w pracy, lub w ruchu, Bitwarden z łatwością zabezpiecza wszystkie Twoje hasła, passkeys i poufne informacje. - Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! + Uznany za najlepszego menedżera haseł przez PCMag, WIRED, The Verge, CNET, G2 i wielu innych! -SECURE YOUR DIGITAL LIFE -Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. +ZABEZPIECZ SWOJE CYFROWE ŻYCIE +Zabezpiecz swoje cyfrowe życie i chroń przed naruszeniami danych, generując i zapisując unikalne, silne hasła do każdego konta. Przechowuj wszystko w zaszyfrowanym end-to-end magazynie haseł, do którego tylko Ty masz dostęp. -ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE -Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. +DOSTĘP DO SWOICH DANYCH W KAŻDYM MIEJSCU, W DOWOLNYM CZASIE, NA KAŻDYM URZĄDZENIU +Z łatwością zarządzaj, przechowuj, zabezpieczaj i udostępniaj nieograniczoną liczbę haseł na nieograniczonej liczbie urządzeń. -EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE -Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. +KAŻDY POWINIEN POSIADAĆ NARZĘDZIA ABY ZACHOWAĆ BEZPIECZEŃSTWO W INTERNECIE +Korzystaj z Bitwarden za darmo, bez reklam i sprzedawania Twoich danych. Bitwarden wierzy, że każdy powinien mieć możliwość zachowania bezpieczeństwa w Internecie. Plany premium oferują dostęp do zaawansowanych funkcji. -EMPOWER YOUR TEAMS WITH BITWARDEN -Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. +WZMOCNIJ SWOJE ZESPOŁY DZIĘKI BITWARDEN +Plany dla Zespołów i Enterprise oferują profesjonalne funkcje biznesowe. Na przykład obejmują integrację z SSO, własny hosting, integrację katalogów i udostępnianie SCIM, zasady globalne, dostęp do API, dzienniki zdarzeń i inne. -Use Bitwarden to secure your workforce and share sensitive information with colleagues. +Użyj Bitwarden, aby zabezpieczyć swoich pracowników i udostępniać poufne informacje współpracownikom. -More reasons to choose Bitwarden: +Więcej powodów, aby wybrać Bitwarden: -World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Szyfrowanie na światowym poziomie +Hasła są chronione za pomocą zaawansowanego, kompleksowego szyfrowania (AES-256-bitowy, solony hashtag i PBKDF2 SHA-256), dzięki czemu Twoje dane pozostają bezpieczne i prywatne. -3rd-party Audits -Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. +Audyty stron trzecich +Bitwarden regularnie przeprowadza kompleksowe audyty bezpieczeństwa stron trzecich we współpracy ze znanymi firmami security. Te coroczne audyty obejmują ocenę kodu źródłowego i testy penetracyjne adresów IP Bitwarden, serwerów i aplikacji internetowych. -Advanced 2FA -Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. +Zaawansowane 2FA +Zabezpiecz swój login za pomocą zewnętrznego narzędzia uwierzytelniającego, kodów przesłanych pocztą elektroniczną lub poświadczeń FIDO2 WebAuthn, takich jak sprzętowy klucz bezpieczeństwa lub hasło. -Bitwarden Send -Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. +Bitwarden Wyślij +Przesyłaj dane bezpośrednio do innych, zachowując kompleksowe szyfrowane bezpieczeństwo i ograniczając ryzyko. -Built-in Generator -Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. +Wbudowany generator +Twórz długie, złożone i różne hasła oraz unikalne nazwy użytkowników dla każdej odwiedzanej witryny. Zintegruj się z dostawcami aliasów e-mail, aby uzyskać dodatkową prywatność. -Global Translations -Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. +Tłumaczenia globalne +Istnieją tłumaczenia Bitwarden na ponad 60 języków, tłumaczone przez globalną społeczność za pośrednictwem Crowdin. -Cross-Platform Applications -Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. +Aplikacje wieloplatformowe +Zabezpiecz i udostępniaj poufne dane w swoim Sejfie Bitwarden z dowolnej przeglądarki, urządzenia mobilnego lub systemu operacyjnego na komputerze stacjonarnym i nie tylko. -Bitwarden secures more than just passwords -End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! +Bitwarden zabezpiecza nie tylko hasła +Rozwiązania do zarządzania danymi zaszyfrownaymi end-to-end od firmy Bitwarden umożliwiają organizacjom zabezpieczanie wszystkiego, w tym tajemnic programistów i kluczy dostępu. Odwiedź Bitwarden.com, aby dowiedzieć się więcej o Mendżerze Sekretów Bitwarden i Bitwarden Passwordless.dev! - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + W domu, w pracy, lub w ruchu, Bitwarden z łatwością zabezpiecza wszystkie Twoje hasła, passkeys i poufne informacje. Synchronizacja i dostęp do sejfu z różnych urządzeń diff --git a/apps/browser/store/locales/pt_BR/copy.resx b/apps/browser/store/locales/pt_BR/copy.resx index 8b99c436d0..067f9357b2 100644 --- a/apps/browser/store/locales/pt_BR/copy.resx +++ b/apps/browser/store/locales/pt_BR/copy.resx @@ -118,10 +118,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Bitwarden Password Manager + Gerenciador de Senhas Bitwarden - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais. Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! @@ -169,7 +169,7 @@ End-to-end encrypted credential management solutions from Bitwarden empower orga - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais. Sincronize e acesse o seu cofre através de múltiplos dispositivos diff --git a/apps/browser/store/locales/zh_CN/copy.resx b/apps/browser/store/locales/zh_CN/copy.resx index 94543f8f6f..d010cb1a7b 100644 --- a/apps/browser/store/locales/zh_CN/copy.resx +++ b/apps/browser/store/locales/zh_CN/copy.resx @@ -118,58 +118,56 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Bitwarden Password Manager + Bitwarden 密码管理器 - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + 无论是在家里、工作中还是在外出时,Bitwarden 都可以轻松地保护您的所有密码、通行密钥和敏感信息。 - Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! + 被 PCMag、WIRED、The Verge、CNET、G2 等评为最佳密码管理器! -SECURE YOUR DIGITAL LIFE -Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. +保护您的数字生活 +通过为每个账户生成并保存独特而强大的密码,保护您的数字生活并防范数据泄露。所有内容保存在只有您可以访问的端对端加密的密码库中。 -ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE -Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. +随时随地在任何设备上访问您的数据 +不受任何限制跨无限数量的设备轻松管理、存储、保护和分享不限数量的密码。 -EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE -Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. +每个人都应该拥有的保持在线安全的工具 +使用 Bitwarden 是免费的,没有广告,不会出售数据。Bitwarden 相信每个人都应该拥有保持在线安全的能力。高级计划提供了堆高级功能的访问。 -EMPOWER YOUR TEAMS WITH BITWARDEN -Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. +通过 BITWARDEN 为您的团队提供支持 +团队和企业计划具有专业的商业功能。例如 SSO 集成、自托管、目录集成和 SCIM 配置、全局策略、API 访问、事件日志等。 -Use Bitwarden to secure your workforce and share sensitive information with colleagues. +使用 Bitwarden 保护您的团队,并与同事共享敏感信息。 +选择 Bitwarden 的更多理由: -More reasons to choose Bitwarden: +世界级加密 +密码受到先进的端对端加密(AES-256 位、加盐哈希标签和 PBKDF2 SHA-256)保护,使您的数据保持安全和私密。 -World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +第三方审计 +Bitwarden 定期与知名的安全公司进行全面的第三方安全审计。这些年度审核包括对 Bitwarden IP、服务器和 Web 应用程序的源代码评估和渗透测试。 -3rd-party Audits -Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. - -Advanced 2FA -Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. +高级两步验证 +使用第三方身份验证器、通过电子邮件发送代码或 FIDO2 WebAuthn 凭据(如硬件安全钥匙或通行密钥)保护您的登录。 Bitwarden Send -Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. +直接传输数据给他人,同时保持端对端加密的安全性并防止曝露。 -Built-in Generator -Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. +内置生成器 +为您访问的每个网站创建长、复杂且独特的密码和用户名。与电子邮件别名提供商集成,增加隐私保护。 -Global Translations -Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. +全球翻译 +Bitwarden 的翻译涵盖 60 多种语言,由全球社区通过 Crowdin 翻译。 -Cross-Platform Applications -Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. +跨平台应用程序 +从任何浏览器、移动设备或桌面操作系统中安全地访问和共享 Bitwarden 密码库中的敏感数据。 -Bitwarden secures more than just passwords -End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! - +Bitwarden 保护的不仅仅是密码 +Bitwarden 的端对端加密凭据管理解决方案使组织能够保护所有内容,包括开发人员机密和通行密钥体验。访问 Bitwarden.com 了解更多关于Bitwarden Secrets Manager 和 Bitwarden Passwordless.dev 的信息! - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + 无论是在家里、工作中还是在外出时,Bitwarden 都可以轻松地保护您的所有密码、通行密钥和敏感信息。 从多台设备同步和访问密码库 diff --git a/apps/browser/tsconfig.json b/apps/browser/tsconfig.json index 505f1533ae..e1bf2b7211 100644 --- a/apps/browser/tsconfig.json +++ b/apps/browser/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "moduleResolution": "node", "noImplicitAny": true, + "allowSyntheticDefaultImports": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "module": "ES2020", diff --git a/apps/cli/package.json b/apps/cli/package.json index b06caacfd4..d6c449de48 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -71,7 +71,7 @@ "papaparse": "5.4.1", "proper-lockfile": "4.1.2", "rxjs": "7.8.1", - "tldts": "6.1.16", + "tldts": "6.1.18", "zxcvbn": "4.4.2" } } diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index a91e876e92..bd61727a6c 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -16,6 +16,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -68,6 +69,7 @@ export class LoginCommand { protected policyApiService: PolicyApiServiceAbstraction, protected orgService: OrganizationService, protected logoutCallback: () => Promise, + protected kdfConfigService: KdfConfigService, ) {} async run(email: string, password: string, options: OptionValues) { @@ -229,7 +231,7 @@ export class LoginCommand { } } if (response.requiresTwoFactor) { - const twoFactorProviders = this.twoFactorService.getSupportedProviders(null); + const twoFactorProviders = await this.twoFactorService.getSupportedProviders(null); if (twoFactorProviders.length === 0) { return Response.badRequest("No providers available for this client."); } @@ -270,7 +272,7 @@ export class LoginCommand { if ( twoFactorToken == null && - response.twoFactorProviders.size > 1 && + Object.keys(response.twoFactorProviders).length > 1 && selectedProvider.type === TwoFactorProviderType.Email ) { const emailReq = new TwoFactorEmailRequest(); @@ -563,14 +565,12 @@ export class LoginCommand { message: "Master Password Hint (optional):", }); const masterPasswordHint = hint.input; - const kdf = await this.stateService.getKdfType(); - const kdfConfig = await this.stateService.getKdfConfig(); + const kdfConfig = await this.kdfConfigService.getKdfConfig(); // Create new key and hash new password const newMasterKey = await this.cryptoService.makeMasterKey( masterPassword, this.email.trim().toLowerCase(), - kdf, kdfConfig, ); const newPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, newMasterKey); diff --git a/apps/cli/src/auth/commands/unlock.command.ts b/apps/cli/src/auth/commands/unlock.command.ts index d52468139a..6b97b59c88 100644 --- a/apps/cli/src/auth/commands/unlock.command.ts +++ b/apps/cli/src/auth/commands/unlock.command.ts @@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request"; @@ -34,6 +35,7 @@ export class UnlockCommand { private syncService: SyncService, private organizationApiService: OrganizationApiServiceAbstraction, private logout: () => Promise, + private kdfConfigService: KdfConfigService, ) {} async run(password: string, cmdOptions: Record) { @@ -48,9 +50,8 @@ export class UnlockCommand { await this.setNewSessionKey(); const email = await this.stateService.getEmail(); - const kdf = await this.stateService.getKdfType(); - const kdfConfig = await this.stateService.getKdfConfig(); - const masterKey = await this.cryptoService.makeMasterKey(password, email, kdf, kdfConfig); + const kdfConfig = await this.kdfConfigService.getKdfConfig(); + const masterKey = await this.cryptoService.makeMasterKey(password, email, kdfConfig); const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; const storedMasterKeyHash = await firstValueFrom( this.masterPasswordService.masterKeyHash$(userId), diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 58329128b8..b3fb68fe63 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -28,14 +28,16 @@ import { ProviderApiService } from "@bitwarden/common/admin-console/services/pro import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service"; -import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; +import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; -import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device-trust-crypto.service.implementation"; +import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; +import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; @@ -77,6 +79,7 @@ import { MigrationBuilderService } from "@bitwarden/common/platform/services/mig import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { StateService } from "@bitwarden/common/platform/services/state.service"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; +import { UserKeyInitService } from "@bitwarden/common/platform/services/user-key-init.service"; import { ActiveUserStateProvider, DerivedStateProvider, @@ -217,7 +220,7 @@ export class Main { syncNotifierService: SyncNotifierService; sendApiService: SendApiService; devicesApiService: DevicesApiServiceAbstraction; - deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction; + deviceTrustService: DeviceTrustServiceAbstraction; authRequestService: AuthRequestService; configApiService: ConfigApiServiceAbstraction; configService: ConfigService; @@ -233,6 +236,8 @@ export class Main { biometricStateService: BiometricStateService; billingAccountProfileStateService: BillingAccountProfileStateService; providerApiService: ProviderApiServiceAbstraction; + userKeyInitService: UserKeyInitService; + kdfConfigService: KdfConfigServiceAbstraction; constructor() { let p = null; @@ -309,7 +314,7 @@ export class Main { this.singleUserStateProvider, ); - this.derivedStateProvider = new DefaultDerivedStateProvider(storageServiceProvider); + this.derivedStateProvider = new DefaultDerivedStateProvider(); this.stateProvider = new DefaultStateProvider( this.activeUserStateProvider, @@ -339,6 +344,7 @@ export class Main { this.storageService, this.logService, new MigrationBuilderService(), + ClientType.Cli, ); this.stateService = new StateService( @@ -355,6 +361,8 @@ export class Main { this.masterPasswordService = new MasterPasswordService(this.stateProvider); + this.kdfConfigService = new KdfConfigService(this.stateProvider); + this.cryptoService = new CryptoService( this.masterPasswordService, this.keyGenerationService, @@ -365,6 +373,7 @@ export class Main { this.stateService, this.accountService, this.stateProvider, + this.kdfConfigService, ); this.appIdService = new AppIdService(this.globalStateProvider); @@ -447,7 +456,11 @@ export class Main { this.stateProvider, ); - this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService); + this.twoFactorService = new TwoFactorService( + this.i18nService, + this.platformUtilsService, + this.globalStateProvider, + ); this.passwordStrengthService = new PasswordStrengthService(); @@ -460,7 +473,7 @@ export class Main { this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); this.devicesApiService = new DevicesApiServiceImplementation(this.apiService); - this.deviceTrustCryptoService = new DeviceTrustCryptoService( + this.deviceTrustService = new DeviceTrustService( this.keyGenerationService, this.cryptoFunctionService, this.cryptoService, @@ -505,11 +518,12 @@ export class Main { this.encryptService, this.passwordStrengthService, this.policyService, - this.deviceTrustCryptoService, + this.deviceTrustService, this.authRequestService, this.userDecryptionOptionsService, this.globalStateProvider, this.billingAccountProfileStateService, + this.kdfConfigService, ); this.authService = new AuthService( @@ -572,6 +586,7 @@ export class Main { this.cryptoService, this.vaultTimeoutSettingsService, this.logService, + this.kdfConfigService, ); this.userVerificationService = new UserVerificationService( @@ -586,6 +601,7 @@ export class Main { this.logService, this.vaultTimeoutSettingsService, this.platformUtilsService, + this.kdfConfigService, ); this.vaultTimeoutService = new VaultTimeoutService( @@ -631,6 +647,7 @@ export class Main { this.avatarService, async (expired: boolean) => await this.logout(), this.billingAccountProfileStateService, + this.tokenService, ); this.totpService = new TotpService(this.cryptoFunctionService, this.logService); @@ -651,7 +668,7 @@ export class Main { this.cipherService, this.cryptoService, this.cryptoFunctionService, - this.stateService, + this.kdfConfigService, ); this.organizationExportService = new OrganizationVaultExportService( @@ -659,8 +676,8 @@ export class Main { this.apiService, this.cryptoService, this.cryptoFunctionService, - this.stateService, this.collectionService, + this.kdfConfigService, ); this.exportService = new VaultExportService( @@ -691,6 +708,12 @@ export class Main { ); this.providerApiService = new ProviderApiService(this.apiService); + + this.userKeyInitService = new UserKeyInitService( + this.accountService, + this.cryptoService, + this.logService, + ); } async run() { @@ -734,6 +757,7 @@ export class Main { this.containerService.attachToGlobal(global); await this.i18nService.init(); this.twoFactorService.init(); + this.userKeyInitService.listenForActiveUserChangesToSetUserKey(); } } diff --git a/apps/cli/src/commands/serve.command.ts b/apps/cli/src/commands/serve.command.ts index 76447f769c..7a11dc4b4a 100644 --- a/apps/cli/src/commands/serve.command.ts +++ b/apps/cli/src/commands/serve.command.ts @@ -134,6 +134,7 @@ export class ServeCommand { this.main.syncService, this.main.organizationApiService, async () => await this.main.logout(), + this.main.kdfConfigService, ); this.sendCreateCommand = new SendCreateCommand( diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index fa71a88f54..5d26b0850e 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -156,6 +156,7 @@ export class Program { this.main.policyApiService, this.main.organizationService, async () => await this.main.logout(), + this.main.kdfConfigService, ); const response = await command.run(email, password, options); this.processResponse(response, true); @@ -265,6 +266,7 @@ export class Program { this.main.syncService, this.main.organizationApiService, async () => await this.main.logout(), + this.main.kdfConfigService, ); const response = await command.run(password, cmd); this.processResponse(response); @@ -627,6 +629,7 @@ export class Program { this.main.syncService, this.main.organizationApiService, this.main.logout, + this.main.kdfConfigService, ); const response = await command.run(null, null); if (!response.success) { diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 4f0d05581c..960d56b036 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -228,7 +228,8 @@ "artifactName": "${productName}-${version}-${arch}.${ext}" }, "snap": { - "summary": "After installation enable required `password-manager-service` by running `sudo snap connect bitwarden:password-manager-service`.", + "summary": "Bitwarden is a secure and free password manager for all of your devices.", + "description": "**Installation**\nBitwarden requires access to the `password-manager-service`. Please enable it through permissions or by running `sudo snap connect bitwarden:password-manager-service` after installation. See https://btwrdn.com/install-snap for details.", "autoStart": true, "base": "core22", "confinement": "strict", diff --git a/apps/desktop/native-messaging-test-runner/package-lock.json b/apps/desktop/native-messaging-test-runner/package-lock.json index e2961eb9ee..747d8ec981 100644 --- a/apps/desktop/native-messaging-test-runner/package-lock.json +++ b/apps/desktop/native-messaging-test-runner/package-lock.json @@ -20,15 +20,17 @@ "devDependencies": { "@tsconfig/node16": "1.0.4", "@types/node": "18.19.29", - "@types/node-ipc": "9.2.0", + "@types/node-ipc": "9.2.3", "typescript": "4.7.4" } }, "../../../libs/common": { + "name": "@bitwarden/common", "version": "0.0.0", "license": "GPL-3.0" }, "../../../libs/node": { + "name": "@bitwarden/node", "version": "0.0.0", "license": "GPL-3.0", "dependencies": { @@ -105,9 +107,9 @@ } }, "node_modules/@types/node-ipc": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@types/node-ipc/-/node-ipc-9.2.0.tgz", - "integrity": "sha512-0v1oucUgINvWPhknecSBE5xkz74sVgeZgiL/LkWXNTSzFaGspEToA4oR56hjza0Jkk6DsS2EiNU3M2R2KQza9A==", + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@types/node-ipc/-/node-ipc-9.2.3.tgz", + "integrity": "sha512-/MvSiF71fYf3+zwqkh/zkVkZj1hl1Uobre9EMFy08mqfJNAmpR0vmPgOUdEIDVgifxHj6G1vYMPLSBLLxoDACQ==", "dev": true, "dependencies": { "@types/node": "*" diff --git a/apps/desktop/native-messaging-test-runner/package.json b/apps/desktop/native-messaging-test-runner/package.json index c572613119..72b2587a4a 100644 --- a/apps/desktop/native-messaging-test-runner/package.json +++ b/apps/desktop/native-messaging-test-runner/package.json @@ -25,7 +25,7 @@ "devDependencies": { "@tsconfig/node16": "1.0.4", "@types/node": "18.19.29", - "@types/node-ipc": "9.2.0", + "@types/node-ipc": "9.2.3", "typescript": "4.7.4" }, "_moduleAliases": { diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 83b73821de..a8301b3b78 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -4,7 +4,6 @@ import { Subject, merge } from "rxjs"; import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; import { SECURE_STORAGE, - STATE_SERVICE_USE_CACHE, LOCALES_DIRECTORY, SYSTEM_LANGUAGE, MEMORY_STORAGE, @@ -16,15 +15,18 @@ import { SafeInjectionToken, STATE_FACTORY, INTRAPROCESS_MESSAGING_SUBJECT, + CLIENT_TYPE, } from "@bitwarden/angular/services/injection-tokens"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; +import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { ClientType } from "@bitwarden/common/enums"; import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -208,7 +210,6 @@ const safeProviders: SafeProvider[] = [ EnvironmentService, TokenService, MigrationRunner, - STATE_SERVICE_USE_CACHE, ], }), safeProvider({ @@ -263,6 +264,7 @@ const safeProviders: SafeProvider[] = [ AccountServiceAbstraction, StateProvider, BiometricStateService, + KdfConfigServiceAbstraction, ], }), safeProvider({ @@ -278,6 +280,10 @@ const safeProviders: SafeProvider[] = [ useClass: NativeMessagingManifestService, deps: [], }), + safeProvider({ + provide: CLIENT_TYPE, + useValue: ClientType.Desktop, + }), safeProvider({ provide: TaskSchedulerService, useClass: DefaultTaskSchedulerService, diff --git a/apps/desktop/src/auth/lock.component.spec.ts b/apps/desktop/src/auth/lock.component.spec.ts index c125eba022..f998e75d7a 100644 --- a/apps/desktop/src/auth/lock.component.spec.ts +++ b/apps/desktop/src/auth/lock.component.spec.ts @@ -13,7 +13,8 @@ import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeou 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 { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service"; @@ -145,8 +146,8 @@ describe("LockComponent", () => { useValue: mock(), }, { - provide: DeviceTrustCryptoServiceAbstraction, - useValue: mock(), + provide: DeviceTrustServiceAbstraction, + useValue: mock(), }, { provide: UserVerificationService, @@ -164,6 +165,10 @@ describe("LockComponent", () => { provide: AccountService, useValue: accountService, }, + { + provide: KdfConfigService, + useValue: mock(), + }, ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); diff --git a/apps/desktop/src/auth/lock.component.ts b/apps/desktop/src/auth/lock.component.ts index 16b58c5bbe..8e87b6663f 100644 --- a/apps/desktop/src/auth/lock.component.ts +++ b/apps/desktop/src/auth/lock.component.ts @@ -10,7 +10,8 @@ import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeou 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 { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { DeviceType } from "@bitwarden/common/enums"; @@ -58,11 +59,12 @@ export class LockComponent extends BaseLockComponent { passwordStrengthService: PasswordStrengthServiceAbstraction, logService: LogService, dialogService: DialogService, - deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + deviceTrustService: DeviceTrustServiceAbstraction, userVerificationService: UserVerificationService, pinCryptoService: PinCryptoServiceAbstraction, biometricStateService: BiometricStateService, accountService: AccountService, + kdfConfigService: KdfConfigService, ) { super( masterPasswordService, @@ -82,11 +84,12 @@ export class LockComponent extends BaseLockComponent { policyService, passwordStrengthService, dialogService, - deviceTrustCryptoService, + deviceTrustService, userVerificationService, pinCryptoService, biometricStateService, accountService, + kdfConfigService, ); } diff --git a/apps/desktop/src/auth/login/login-via-auth-request.component.ts b/apps/desktop/src/auth/login/login-via-auth-request.component.ts index 0a339030ba..2d0f560205 100644 --- a/apps/desktop/src/auth/login/login-via-auth-request.component.ts +++ b/apps/desktop/src/auth/login/login-via-auth-request.component.ts @@ -13,7 +13,7 @@ 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 { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; 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"; @@ -55,7 +55,7 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { syncService: SyncService, stateService: StateService, loginEmailService: LoginEmailServiceAbstraction, - deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + deviceTrustService: DeviceTrustServiceAbstraction, authRequestService: AuthRequestServiceAbstraction, loginStrategyService: LoginStrategyServiceAbstraction, accountService: AccountService, @@ -77,7 +77,7 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { validationService, stateService, loginEmailService, - deviceTrustCryptoService, + deviceTrustService, authRequestService, loginStrategyService, accountService, diff --git a/apps/desktop/src/auth/set-password.component.ts b/apps/desktop/src/auth/set-password.component.ts index 93dfe0abd8..feea5edd86 100644 --- a/apps/desktop/src/auth/set-password.component.ts +++ b/apps/desktop/src/auth/set-password.component.ts @@ -9,6 +9,7 @@ import { OrganizationUserService } from "@bitwarden/common/admin-console/abstrac import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -52,6 +53,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, ssoLoginService: SsoLoginServiceAbstraction, dialogService: DialogService, + kdfConfigService: KdfConfigService, ) { super( accountService, @@ -73,6 +75,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On userDecryptionOptionsService, ssoLoginService, dialogService, + kdfConfigService, ); } diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index afdfc90d76..97067b788a 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 7869b0894b..2d25269fff 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -2697,6 +2697,9 @@ "message": "تنسيقات مشتركة", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index d4cea4f06e..1ecd18eee7 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -2697,6 +2697,9 @@ "message": "Ortaq formatlar", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Uğurlu" + }, "troubleshooting": { "message": "Problemlərin aradan qaldırılması" }, diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index 53e3ec2d12..e0133e5a74 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index f4886c420f..d53034d61c 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -2697,6 +2697,9 @@ "message": "Често използвани формати", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Успех" + }, "troubleshooting": { "message": "Отстраняване на проблеми" }, diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index abd2c1cfae..626734ebff 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index 825bd6344e..9d5685cca9 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index 6c48d6cb0b..d8c0f32948 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -2697,6 +2697,9 @@ "message": "Formats comuns", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Resolució de problemes" }, diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index 550b10a31c..e68fe8fffc 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -2697,6 +2697,9 @@ "message": "Společné formáty", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Úspěch" + }, "troubleshooting": { "message": "Řešení problémů" }, diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index b1cc9e63d3..62f2e608bb 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index f2a84a3c29..0e578a6f66 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -2697,6 +2697,9 @@ "message": "Almindelige formater", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Gennemført" + }, "troubleshooting": { "message": "Fejlfinding" }, diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index e5e3945abc..d04c2795f3 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -1633,10 +1633,10 @@ "message": "Browser-Integration wird nicht unterstützt" }, "browserIntegrationErrorTitle": { - "message": "Error enabling browser integration" + "message": "Fehler beim Aktivieren der Browser-Integration" }, "browserIntegrationErrorDesc": { - "message": "An error has occurred while enabling browser integration." + "message": "Beim Aktivieren der Browser-Integration ist ein Fehler aufgetreten." }, "browserIntegrationMasOnlyDesc": { "message": "Leider wird die Browser-Integration derzeit nur in der Mac App Store Version unterstützt." @@ -2697,6 +2697,9 @@ "message": "Gängigste Formate", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Erfolg" + }, "troubleshooting": { "message": "Problembehandlung" }, diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 41e6a62a2f..87360c33ce 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -2697,6 +2697,9 @@ "message": "Κοινές μορφές", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Αντιμετώπιση Προβλημάτων" }, diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index 2658610df3..5c8c32b7c1 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 0542da9ddc..abfa0b1c0d 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 1c4cc4f0be..427f08f805 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index ec5da44293..f7df93bdd7 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 3850cc1d85..02cd737baa 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index b21108b6ad..2067b2dcc2 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index 08356d410d..ef34f8222a 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -2697,6 +2697,9 @@ "message": "فرمت‌های رایج", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index fca24c197a..517b437d03 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -2697,6 +2697,9 @@ "message": "Yleiset muodot", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Onnistui" + }, "troubleshooting": { "message": "Vianetsintä" }, diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index 6d5f85fca8..d28a4b568c 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index 1097624b14..e82420a1f5 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -1636,7 +1636,7 @@ "message": "Error enabling browser integration" }, "browserIntegrationErrorDesc": { - "message": "An error has occurred while enabling browser integration." + "message": "Une erreur s'est produite lors de l'action de l'intégration du navigateur." }, "browserIntegrationMasOnlyDesc": { "message": "Malheureusement l'intégration avec le navigateur est uniquement supportée dans la version Mac App Store pour le moment." @@ -2697,6 +2697,9 @@ "message": "Formats communs", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Succès" + }, "troubleshooting": { "message": "Résolution de problèmes" }, diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 90648699c0..889a2beeee 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 73599c012e..3b155ffdf3 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -2697,6 +2697,9 @@ "message": "תסדירים נפוצים", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 4f8bb9b4bb..af28c66681 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 220c8bfab2..01983d5891 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 149d48284e..838b3fc7c8 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -2697,6 +2697,9 @@ "message": "Általános formátumok", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Sikeres" + }, "troubleshooting": { "message": "Hibaelhárítás" }, diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index 3194b0f7d3..2173224f54 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 08ae2d9da8..93882cf698 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -2697,6 +2697,9 @@ "message": "Formati comuni", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Successo" + }, "troubleshooting": { "message": "Risoluzione problemi" }, diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index b07eab20cc..ab6c0be95f 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -2697,6 +2697,9 @@ "message": "一般的な形式", "description": "Label indicating the most common import formats" }, + "success": { + "message": "成功" + }, "troubleshooting": { "message": "トラブルシューティング" }, diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 90648699c0..889a2beeee 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 90648699c0..889a2beeee 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index 162cba3a75..eb0cbcf6be 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 09b1767af0..8e50ade96c 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index de77aa8fbf..e9de697005 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -2697,6 +2697,9 @@ "message": "Dažni formatai", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index 521a0afcf2..e2e068362e 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -2697,6 +2697,9 @@ "message": "Izplatīti veidoli", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Izdevās" + }, "troubleshooting": { "message": "Sarežģījumu novēršana" }, diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index ed458379b8..1f49961b46 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index b94b9d1b79..96811b9dba 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 90648699c0..889a2beeee 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index 5142c8e61f..0ee0db69ef 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index e190cfc236..7bf132bdac 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -2697,6 +2697,9 @@ "message": "Vanlige formater", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index bd58a18b0d..13e1466805 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 3ca0730710..f56572259b 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -2697,6 +2697,9 @@ "message": "Veelvoorkomende formaten", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Succes" + }, "troubleshooting": { "message": "Probleemoplossing" }, diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 12e11b32c1..35e7173d74 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index 7363558551..cd83d2ea69 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index df7a158a3a..250c557309 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -2697,6 +2697,9 @@ "message": "Popularne formaty", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Sukces" + }, "troubleshooting": { "message": "Rozwiązywanie problemów" }, diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index f651e0b060..12db01d8cd 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -561,10 +561,10 @@ "message": "A sua nova conta foi criada! Agora você pode iniciar a sessão." }, "youSuccessfullyLoggedIn": { - "message": "You successfully logged in" + "message": "Você logou na sua conta com sucesso" }, "youMayCloseThisWindow": { - "message": "You may close this window" + "message": "Você pode fechar esta janela" }, "masterPassSent": { "message": "Enviamos um e-mail com a dica da sua senha mestra." @@ -801,10 +801,10 @@ "message": "Alterar Senha Mestra" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Continuar no aplicativo web?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Você pode alterar a sua senha mestra no aplicativo web Bitwarden." }, "fingerprintPhrase": { "message": "Frase biométrica", @@ -1402,7 +1402,7 @@ "message": "Código PIN inválido." }, "tooManyInvalidPinEntryAttemptsLoggingOut": { - "message": "Too many invalid PIN entry attempts. Logging out." + "message": "Muitas tentativas de entrada de PIN inválidas. Desconectando." }, "unlockWithWindowsHello": { "message": "Desbloquear com o Windows Hello" @@ -1557,7 +1557,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": "Verificação necessária", "description": "Default title for the user verification dialog." }, "currentMasterPass": { @@ -1633,10 +1633,10 @@ "message": "Integração com o navegador não suportado" }, "browserIntegrationErrorTitle": { - "message": "Error enabling browser integration" + "message": "Erro ao ativar a integração do navegador" }, "browserIntegrationErrorDesc": { - "message": "An error has occurred while enabling browser integration." + "message": "Ocorreu um erro ao permitir a integração do navegador." }, "browserIntegrationMasOnlyDesc": { "message": "Infelizmente, por ora, a integração do navegador só é suportada na versão da Mac App Store." @@ -1654,10 +1654,10 @@ "message": "Ative uma camada adicional de segurança, exigindo validação de frase de impressão digital ao estabelecer uma ligação entre o computador e o navegador. Quando ativado, isto requer intervenção do usuário e verificação cada vez que uma conexão é estabelecida." }, "enableHardwareAcceleration": { - "message": "Use hardware acceleration" + "message": "Utilizar aceleração de hardware" }, "enableHardwareAccelerationDesc": { - "message": "By default this setting is ON. Turn OFF only if you experience graphical issues. Restart is required." + "message": "Por padrão esta configuração está ativada. Desligar apenas se tiver problemas gráficos. Reiniciar é necessário." }, "approve": { "message": "Aprovar" @@ -1898,40 +1898,40 @@ "message": "A sua senha mestra não atende a uma ou mais das políticas da sua organização. Para acessar o cofre, você deve atualizar a sua senha mestra agora. O processo desconectará você da sessão atual, exigindo que você inicie a sessão novamente. Sessões ativas em outros dispositivos podem continuar ativas por até uma hora." }, "tryAgain": { - "message": "Try again" + "message": "Tentar novamente" }, "verificationRequiredForActionSetPinToContinue": { - "message": "Verification required for this action. Set a PIN to continue." + "message": "Verificação necessária para esta ação. Defina um PIN para continuar." }, "setPin": { - "message": "Set PIN" + "message": "Definir PIN" }, "verifyWithBiometrics": { - "message": "Verify with biometrics" + "message": "Verificiar com biometria" }, "awaitingConfirmation": { - "message": "Awaiting confirmation" + "message": "Aguardando confirmação" }, "couldNotCompleteBiometrics": { - "message": "Could not complete biometrics." + "message": "Não foi possível completar a biometria." }, "needADifferentMethod": { - "message": "Need a different method?" + "message": "Precisa de um método diferente?" }, "useMasterPassword": { - "message": "Use master password" + "message": "Usar a senha mestra" }, "usePin": { - "message": "Use PIN" + "message": "Usar PIN" }, "useBiometrics": { - "message": "Use biometrics" + "message": "Usar biometria" }, "enterVerificationCodeSentToEmail": { - "message": "Enter the verification code that was sent to your email." + "message": "Digite o código de verificação que foi enviado para o seu e-mail." }, "resendCode": { - "message": "Resend code" + "message": "Reenviar código" }, "hours": { "message": "Horas" @@ -2541,13 +2541,13 @@ } }, "launchDuoAndFollowStepsToFinishLoggingIn": { - "message": "Launch Duo and follow the steps to finish logging in." + "message": "Inicie o Duo e siga os passos para finalizar o login." }, "duoRequiredByOrgForAccount": { - "message": "Duo two-step login is required for your account." + "message": "A autenticação em duas etapas do Duo é necessária para sua conta." }, "launchDuo": { - "message": "Launch Duo in Browser" + "message": "Iniciar o Duo no navegador" }, "importFormatError": { "message": "Os dados não estão formatados corretamente. Por favor, verifique o seu arquivo de importação e tente novamente." @@ -2630,13 +2630,13 @@ "message": "Nome de usuário ou senha incorretos" }, "incorrectPassword": { - "message": "Incorrect password" + "message": "Senha incorreta" }, "incorrectCode": { - "message": "Incorrect code" + "message": "Código incorreto" }, "incorrectPin": { - "message": "Incorrect PIN" + "message": "PIN incorreto" }, "multifactorAuthenticationFailed": { "message": "Falha na autenticação de múltiplos fatores" @@ -2697,25 +2697,28 @@ "message": "Formatos comuns", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { - "message": "Troubleshooting" + "message": "Solução de problemas" }, "disableHardwareAccelerationRestart": { - "message": "Disable hardware acceleration and restart" + "message": "Desativar aceleração de hardware e reiniciar" }, "enableHardwareAccelerationRestart": { - "message": "Enable hardware acceleration and restart" + "message": "Ativar aceleração de hardware e reiniciar" }, "removePasskey": { - "message": "Remove passkey" + "message": "Remover senha" }, "passkeyRemoved": { - "message": "Passkey removed" + "message": "Chave de acesso removida" }, "errorAssigningTargetCollection": { - "message": "Error assigning target collection." + "message": "Erro ao atribuir coleção de destino." }, "errorAssigningTargetFolder": { - "message": "Error assigning target folder." + "message": "Erro ao atribuir pasta de destino." } } diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 4e58dad2cf..14f0ec5d2f 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -2697,6 +2697,9 @@ "message": "Formatos comuns", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Com sucesso" + }, "troubleshooting": { "message": "Resolução de problemas" }, diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index 3fe73f28a7..978f57eb9b 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index cc182812a6..c9b3b95b39 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -2697,6 +2697,9 @@ "message": "Основные форматы", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Успешно" + }, "troubleshooting": { "message": "Устранение проблем" }, diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 261ae1c9b8..3d43997144 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 6ef52a83ee..6499486b9d 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -2697,6 +2697,9 @@ "message": "Bežné formáty", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Úspech" + }, "troubleshooting": { "message": "Riešenie problémov" }, diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index 8c9c158c87..8cb06dcf0c 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index edafdb55a2..04b7e4cf29 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -801,10 +801,10 @@ "message": "Промени главну лозинку" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Ићи на веб апликацију?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Можете променити главну лозинку на Bitwarden веб апликацији." }, "fingerprintPhrase": { "message": "Сигурносна Фраза Сефа", @@ -1633,10 +1633,10 @@ "message": "Интеграција са претраживачем није подржана" }, "browserIntegrationErrorTitle": { - "message": "Error enabling browser integration" + "message": "Грешка при омогућавању интеграције прегледача" }, "browserIntegrationErrorDesc": { - "message": "An error has occurred while enabling browser integration." + "message": "Дошло је до грешке при омогућавању интеграције прегледача." }, "browserIntegrationMasOnlyDesc": { "message": "Нажалост, интеграција прегледача за сада је подржана само у верзији Mac App Store." @@ -2697,6 +2697,9 @@ "message": "Уобичајени формати", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Решавање проблема" }, @@ -2713,9 +2716,9 @@ "message": "Приступачни кључ је уклоњен" }, "errorAssigningTargetCollection": { - "message": "Error assigning target collection." + "message": "Грешка при додељивању циљне колекције." }, "errorAssigningTargetFolder": { - "message": "Error assigning target folder." + "message": "Грешка при додељивању циљне фасцикле." } } diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 6342424fd4..bd21c0f328 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -2697,6 +2697,9 @@ "message": "Vanliga format", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Felsökning" }, diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 90648699c0..889a2beeee 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index 5b6a1b9d0b..f1cd5351f7 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 42a8f207c7..3e7229c41b 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Sorun giderme" }, diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index ac7b7c3243..9ee7652093 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -2697,6 +2697,9 @@ "message": "Поширені формати", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Успішно" + }, "troubleshooting": { "message": "Усунення проблем" }, diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index aac9995db1..0c0e6f6df7 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -2697,6 +2697,9 @@ "message": "Common formats", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "Troubleshooting" }, diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 0560466cf8..aad13e06ef 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -801,10 +801,10 @@ "message": "修改主密码" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "前往网页 App 吗?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "您可以在 Bitwarden 网页应用上更改您的主密码。" }, "fingerprintPhrase": { "message": "指纹短语", @@ -2697,6 +2697,9 @@ "message": "常规格式", "description": "Label indicating the most common import formats" }, + "success": { + "message": "成功" + }, "troubleshooting": { "message": "故障排除" }, diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 9eb12e23cf..5f768b0a43 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -2697,6 +2697,9 @@ "message": "常見格式", "description": "Label indicating the most common import formats" }, + "success": { + "message": "Success" + }, "troubleshooting": { "message": "疑難排解" }, diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index bffd2002ff..d11fceeacc 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -6,6 +6,7 @@ import { Subject, firstValueFrom } from "rxjs"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service"; import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; +import { ClientType } from "@bitwarden/common/enums"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; @@ -157,7 +158,7 @@ export class Main { activeUserStateProvider, singleUserStateProvider, globalStateProvider, - new DefaultDerivedStateProvider(storageServiceProvider), + new DefaultDerivedStateProvider(), ); this.environmentService = new DefaultEnvironmentService(stateProvider, accountService); @@ -190,6 +191,7 @@ export class Main { this.storageService, this.logService, new MigrationBuilderService(), + ClientType.Desktop, ); // TODO: this state service will have access to on disk storage, but not in memory storage. @@ -205,7 +207,6 @@ export class Main { this.environmentService, this.tokenService, this.migrationRunner, - false, // Do not use disk caching because this will get out of sync with the renderer service ); this.desktopSettingsService = new DesktopSettingsService(stateProvider); diff --git a/apps/desktop/src/platform/services/desktop-settings.service.ts b/apps/desktop/src/platform/services/desktop-settings.service.ts index d967e5fb1d..09ddad07c1 100644 --- a/apps/desktop/src/platform/services/desktop-settings.service.ts +++ b/apps/desktop/src/platform/services/desktop-settings.service.ts @@ -164,7 +164,7 @@ export class DesktopSettingsService { /** * Sets the setting for whether or not the application should be shown in the dock. - * @param value `true` if the application should should in the dock, `false` if it should not. + * @param value `true` if the application should show in the dock, `false` if it should not. */ async setAlwaysShowDock(value: boolean) { await this.alwaysShowDockState.update(() => value); diff --git a/apps/desktop/src/platform/services/electron-crypto.service.spec.ts b/apps/desktop/src/platform/services/electron-crypto.service.spec.ts index 3d9171b52e..86463dccaa 100644 --- a/apps/desktop/src/platform/services/electron-crypto.service.spec.ts +++ b/apps/desktop/src/platform/services/electron-crypto.service.spec.ts @@ -1,6 +1,7 @@ import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider"; import { mock } from "jest-mock-extended"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -35,6 +36,7 @@ describe("electronCryptoService", () => { let accountService: FakeAccountService; let stateProvider: FakeStateProvider; const biometricStateService = mock(); + const kdfConfigService = mock(); const mockUserId = "mock user id" as UserId; @@ -54,6 +56,7 @@ describe("electronCryptoService", () => { accountService, stateProvider, biometricStateService, + kdfConfigService, ); }); diff --git a/apps/desktop/src/platform/services/electron-crypto.service.ts b/apps/desktop/src/platform/services/electron-crypto.service.ts index d113a18200..0ed0f73d41 100644 --- a/apps/desktop/src/platform/services/electron-crypto.service.ts +++ b/apps/desktop/src/platform/services/electron-crypto.service.ts @@ -1,6 +1,7 @@ import { firstValueFrom } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; @@ -31,6 +32,7 @@ export class ElectronCryptoService extends CryptoService { accountService: AccountService, stateProvider: StateProvider, private biometricStateService: BiometricStateService, + kdfConfigService: KdfConfigService, ) { super( masterPasswordService, @@ -42,6 +44,7 @@ export class ElectronCryptoService extends CryptoService { stateService, accountService, stateProvider, + kdfConfigService, ); } diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts index b1a84c22f3..7de0c98cd5 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts @@ -58,7 +58,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { protected showPaymentMethodWarningBanners$ = this.configService.getFeatureFlag$( FeatureFlag.ShowPaymentMethodWarningBanners, - false, ); constructor( diff --git a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts index dea6f4999b..b18effac86 100644 --- a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts +++ b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts @@ -194,7 +194,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy { }), ); }), - shareReplay({ refCount: false }), + shareReplay({ refCount: true, bufferSize: 1 }), ); restrictGroupAccess$ = combineLatest([ diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts index f1af950650..3cccd6e28f 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts @@ -218,7 +218,6 @@ export class MemberDialogComponent implements OnDestroy { groups: groups$, flexibleCollectionsV1Enabled: this.configService.getFeatureFlag$( FeatureFlag.FlexibleCollectionsV1, - false, ), }) .pipe(takeUntil(this.destroy$)) diff --git a/apps/web/src/app/admin-console/organizations/members/people.component.ts b/apps/web/src/app/admin-console/organizations/members/people.component.ts index 0df247d7b0..af04d83c34 100644 --- a/apps/web/src/app/admin-console/organizations/members/people.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/people.component.ts @@ -37,7 +37,7 @@ import { import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; -import { OrganizationBillingServiceAbstraction as OrganizationBillingService } from "@bitwarden/common/billing/abstractions/organization-billing.service"; +import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billilng-api.service.abstraction"; import { ProductType } from "@bitwarden/common/enums"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -121,7 +121,7 @@ export class PeopleComponent extends BasePeopleComponent { private groupService: GroupService, private collectionService: CollectionService, organizationManagementPreferencesService: OrganizationManagementPreferencesService, - private organizationBillingService: OrganizationBillingService, + private billingApiService: BillingApiServiceAbstraction, ) { super( apiService, @@ -190,10 +190,11 @@ export class PeopleComponent extends BasePeopleComponent { .find((p) => p.organizationId === this.organization.id); this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled; - this.orgIsOnSecretsManagerStandalone = - await this.organizationBillingService.isOnSecretsManagerStandalone( - this.organization.id, - ); + const billingMetadata = await this.billingApiService.getOrganizationBillingMetadata( + this.organization.id, + ); + + this.orgIsOnSecretsManagerStandalone = billingMetadata.isOnSecretsManagerStandalone; await this.load(); diff --git a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts index cd94513f19..fcdbe1e496 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service.ts @@ -7,10 +7,15 @@ import { OrganizationUserResetPasswordRequest, OrganizationUserResetPasswordWithIdRequest, } from "@bitwarden/common/admin-console/abstractions/organization-user/requests"; -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; +import { + Argon2KdfConfig, + KdfConfig, + PBKDF2KdfConfig, +} from "@bitwarden/common/auth/models/domain/kdf-config"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { KdfType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; @@ -90,12 +95,17 @@ export class OrganizationUserResetPasswordService { const decValue = await this.cryptoService.rsaDecrypt(response.resetPasswordKey, decPrivateKey); const existingUserKey = new SymmetricCryptoKey(decValue) as UserKey; + // determine Kdf Algorithm + const kdfConfig: KdfConfig = + response.kdf === KdfType.PBKDF2_SHA256 + ? new PBKDF2KdfConfig(response.kdfIterations) + : new Argon2KdfConfig(response.kdfIterations, response.kdfMemory, response.kdfParallelism); + // Create new master key and hash new password const newMasterKey = await this.cryptoService.makeMasterKey( newMasterPassword, email.trim().toLowerCase(), - response.kdf, - new KdfConfig(response.kdfIterations, response.kdfMemory, response.kdfParallelism), + kdfConfig, ); const newMasterKeyHash = await this.cryptoService.hashMasterKey( newMasterPassword, diff --git a/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.html b/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.html index 3286c08689..d0be72a52e 100644 --- a/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.html @@ -2,15 +2,7 @@ {{ "twoStepLoginPolicyWarning" | i18n }} -

-
- - -
-
+ + + {{ "turnOn" | i18n }} + diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.ts b/apps/web/src/app/admin-console/organizations/settings/account.component.ts index 1ce05f7a30..d8091e46ae 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.ts +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.ts @@ -44,12 +44,10 @@ export class AccountComponent { protected flexibleCollectionsMigrationEnabled$ = this.configService.getFeatureFlag$( FeatureFlag.FlexibleCollectionsMigration, - false, ); flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$( FeatureFlag.FlexibleCollectionsV1, - false, ); // FormGroup validators taken from server Organization domain object diff --git a/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts b/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts index abf1d249e1..80d77968f2 100644 --- a/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts +++ b/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts @@ -10,6 +10,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { DialogService } from "@bitwarden/components"; import { TwoFactorDuoComponent } from "../../../auth/settings/two-factor-duo.component"; import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../../auth/settings/two-factor-setup.component"; @@ -22,6 +23,7 @@ import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../.. export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent { tabbedHeader = false; constructor( + dialogService: DialogService, apiService: ApiService, modalService: ModalService, messagingService: MessagingService, @@ -31,6 +33,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent { billingAccountProfileStateService: BillingAccountProfileStateService, ) { super( + dialogService, apiService, modalService, messagingService, diff --git a/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts b/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts index 6bcb933e51..dbc1ce820c 100644 --- a/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts +++ b/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts @@ -3,10 +3,15 @@ import { Injectable } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; +import { + Argon2KdfConfig, + KdfConfig, + PBKDF2KdfConfig, +} from "@bitwarden/common/auth/models/domain/kdf-config"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { KdfType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; @@ -231,16 +236,22 @@ export class EmergencyAccessService { const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey; - const masterKey = await this.cryptoService.makeMasterKey( - masterPassword, - email, - takeoverResponse.kdf, - new KdfConfig( - takeoverResponse.kdfIterations, - takeoverResponse.kdfMemory, - takeoverResponse.kdfParallelism, - ), - ); + let config: KdfConfig; + + switch (takeoverResponse.kdf) { + case KdfType.PBKDF2_SHA256: + config = new PBKDF2KdfConfig(takeoverResponse.kdfIterations); + break; + case KdfType.Argon2id: + config = new Argon2KdfConfig( + takeoverResponse.kdfIterations, + takeoverResponse.kdfMemory, + takeoverResponse.kdfParallelism, + ); + break; + } + + const masterKey = await this.cryptoService.makeMasterKey(masterPassword, email, config); const masterKeyHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey); const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, grantorUserKey); diff --git a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts index 0997f18864..ec68556931 100644 --- a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts +++ b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts @@ -1,7 +1,8 @@ import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -42,11 +43,12 @@ describe("KeyRotationService", () => { let mockSendService: MockProxy; let mockEmergencyAccessService: MockProxy; let mockResetPasswordService: MockProxy; - let mockDeviceTrustCryptoService: MockProxy; + let mockDeviceTrustService: MockProxy; let mockCryptoService: MockProxy; let mockEncryptService: MockProxy; let mockStateService: MockProxy; let mockConfigService: MockProxy; + let mockKdfConfigService: MockProxy; const mockUserId = Utils.newGuid() as UserId; const mockAccountService: FakeAccountService = mockAccountServiceWith(mockUserId); @@ -60,11 +62,12 @@ describe("KeyRotationService", () => { mockSendService = mock(); mockEmergencyAccessService = mock(); mockResetPasswordService = mock(); - mockDeviceTrustCryptoService = mock(); + mockDeviceTrustService = mock(); mockCryptoService = mock(); mockEncryptService = mock(); mockStateService = mock(); mockConfigService = mock(); + mockKdfConfigService = mock(); keyRotationService = new UserKeyRotationService( mockMasterPasswordService, @@ -74,12 +77,13 @@ describe("KeyRotationService", () => { mockSendService, mockEmergencyAccessService, mockResetPasswordService, - mockDeviceTrustCryptoService, + mockDeviceTrustService, mockCryptoService, mockEncryptService, mockStateService, mockAccountService, mockConfigService, + mockKdfConfigService, ); }); diff --git a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts index f5812d341a..dc5f933724 100644 --- a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts +++ b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts @@ -2,7 +2,8 @@ import { Injectable } from "@angular/core"; import { firstValueFrom } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -33,12 +34,13 @@ export class UserKeyRotationService { private sendService: SendService, private emergencyAccessService: EmergencyAccessService, private resetPasswordService: OrganizationUserResetPasswordService, - private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + private deviceTrustService: DeviceTrustServiceAbstraction, private cryptoService: CryptoService, private encryptService: EncryptService, private stateService: StateService, private accountService: AccountService, private configService: ConfigService, + private kdfConfigService: KdfConfigService, ) {} /** @@ -54,8 +56,7 @@ export class UserKeyRotationService { const masterKey = await this.cryptoService.makeMasterKey( masterPassword, await this.stateService.getEmail(), - await this.stateService.getKdfType(), - await this.stateService.getKdfConfig(), + await this.kdfConfigService.getKdfConfig(), ); if (!masterKey) { @@ -89,14 +90,14 @@ export class UserKeyRotationService { request.emergencyAccessKeys = await this.emergencyAccessService.getRotatedKeys(newUserKey); request.resetPasswordKeys = await this.resetPasswordService.getRotatedKeys(newUserKey); - if (await this.configService.getFeatureFlag(FeatureFlag.KeyRotationImprovements)) { + if (await this.configService.getFeatureFlag(FeatureFlag.KeyRotationImprovements)) { await this.apiService.postUserKeyUpdate(request); } else { await this.rotateUserKeyAndEncryptedDataLegacy(request); } const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - await this.deviceTrustCryptoService.rotateDevicesTrust( + await this.deviceTrustService.rotateDevicesTrust( activeAccount.id, newUserKey, masterPasswordHash, diff --git a/apps/web/src/app/auth/settings/account/change-email.component.ts b/apps/web/src/app/auth/settings/account/change-email.component.ts index 372b344b10..e5a3c72337 100644 --- a/apps/web/src/app/auth/settings/account/change-email.component.ts +++ b/apps/web/src/app/auth/settings/account/change-email.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { EmailTokenRequest } from "@bitwarden/common/auth/models/request/email-token.request"; import { EmailRequest } from "@bitwarden/common/auth/models/request/email.request"; @@ -37,6 +38,7 @@ export class ChangeEmailComponent implements OnInit { private logService: LogService, private stateService: StateService, private formBuilder: FormBuilder, + private kdfConfigService: KdfConfigService, ) {} async ngOnInit() { @@ -83,12 +85,10 @@ export class ChangeEmailComponent implements OnInit { step1Value.masterPassword, await this.cryptoService.getOrDeriveMasterKey(step1Value.masterPassword), ); - const kdf = await this.stateService.getKdfType(); - const kdfConfig = await this.stateService.getKdfConfig(); + const kdfConfig = await this.kdfConfigService.getKdfConfig(); const newMasterKey = await this.cryptoService.makeMasterKey( step1Value.masterPassword, newEmail, - kdf, kdfConfig, ); request.newMasterPasswordHash = await this.cryptoService.hashMasterKey( diff --git a/apps/web/src/app/auth/settings/change-password.component.ts b/apps/web/src/app/auth/settings/change-password.component.ts index 6d16893170..454d96f2bd 100644 --- a/apps/web/src/app/auth/settings/change-password.component.ts +++ b/apps/web/src/app/auth/settings/change-password.component.ts @@ -5,6 +5,7 @@ import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitward import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -48,6 +49,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { dialogService: DialogService, private userVerificationService: UserVerificationService, private keyRotationService: UserKeyRotationService, + kdfConfigService: KdfConfigService, ) { super( i18nService, @@ -58,6 +60,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { policyService, stateService, dialogService, + kdfConfigService, ); } diff --git a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts index 575c6f4a23..73b1fa775d 100644 --- a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts @@ -5,6 +5,7 @@ import { takeUntil } from "rxjs"; import { ChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -58,6 +59,7 @@ export class EmergencyAccessTakeoverComponent private logService: LogService, dialogService: DialogService, private dialogRef: DialogRef, + kdfConfigService: KdfConfigService, ) { super( i18nService, @@ -68,6 +70,7 @@ export class EmergencyAccessTakeoverComponent policyService, stateService, dialogService, + kdfConfigService, ); } diff --git a/apps/web/src/app/auth/settings/security/change-kdf/change-kdf-confirmation.component.ts b/apps/web/src/app/auth/settings/security/change-kdf/change-kdf-confirmation.component.ts index 0284c665d8..985fb3e038 100644 --- a/apps/web/src/app/auth/settings/security/change-kdf/change-kdf-confirmation.component.ts +++ b/apps/web/src/app/auth/settings/security/change-kdf/change-kdf-confirmation.component.ts @@ -3,6 +3,7 @@ import { Component, Inject } from "@angular/core"; import { FormGroup, FormControl, Validators } from "@angular/forms"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { KdfRequest } from "@bitwarden/common/models/request/kdf.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -18,7 +19,6 @@ import { KdfType } from "@bitwarden/common/platform/enums"; templateUrl: "change-kdf-confirmation.component.html", }) export class ChangeKdfConfirmationComponent { - kdf: KdfType; kdfConfig: KdfConfig; form = new FormGroup({ @@ -37,9 +37,9 @@ export class ChangeKdfConfirmationComponent { private messagingService: MessagingService, private stateService: StateService, private logService: LogService, - @Inject(DIALOG_DATA) params: { kdf: KdfType; kdfConfig: KdfConfig }, + private kdfConfigService: KdfConfigService, + @Inject(DIALOG_DATA) params: { kdfConfig: KdfConfig }, ) { - this.kdf = params.kdf; this.kdfConfig = params.kdfConfig; this.masterPassword = null; } @@ -65,22 +65,24 @@ export class ChangeKdfConfirmationComponent { private async makeKeyAndSaveAsync() { const masterPassword = this.form.value.masterPassword; + + // Ensure the KDF config is valid. + this.kdfConfig.validateKdfConfig(); + const request = new KdfRequest(); - request.kdf = this.kdf; + request.kdf = this.kdfConfig.kdfType; request.kdfIterations = this.kdfConfig.iterations; - request.kdfMemory = this.kdfConfig.memory; - request.kdfParallelism = this.kdfConfig.parallelism; + if (this.kdfConfig.kdfType === KdfType.Argon2id) { + request.kdfMemory = this.kdfConfig.memory; + request.kdfParallelism = this.kdfConfig.parallelism; + } const masterKey = await this.cryptoService.getOrDeriveMasterKey(masterPassword); request.masterPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey); const email = await this.stateService.getEmail(); - // Ensure the KDF config is valid. - this.cryptoService.validateKdfConfig(this.kdf, this.kdfConfig); - const newMasterKey = await this.cryptoService.makeMasterKey( masterPassword, email, - this.kdf, this.kdfConfig, ); request.newMasterPasswordHash = await this.cryptoService.hashMasterKey( diff --git a/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.html b/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.html index 9b16c446be..8b1dec8e13 100644 --- a/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.html +++ b/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.html @@ -19,14 +19,14 @@ - +
- + - +
- +

{{ "kdfIterationsDesc" | i18n: (PBKDF2_ITERATIONS.defaultValue | number) }}

@@ -100,7 +100,7 @@ {{ "kdfIterationsWarning" | i18n: (100000 | number) }}
- +

{{ "argon2Desc" | i18n }}

{{ "argon2Warning" | i18n }}
diff --git a/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.ts b/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.ts index d91fb8d083..5c05f1ba2a 100644 --- a/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.ts +++ b/apps/web/src/app/auth/settings/security/change-kdf/change-kdf.component.ts @@ -1,7 +1,11 @@ import { Component, OnInit } from "@angular/core"; -import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; +import { + Argon2KdfConfig, + KdfConfig, + PBKDF2KdfConfig, +} from "@bitwarden/common/auth/models/domain/kdf-config"; import { DEFAULT_KDF_CONFIG, PBKDF2_ITERATIONS, @@ -19,7 +23,6 @@ import { ChangeKdfConfirmationComponent } from "./change-kdf-confirmation.compon templateUrl: "change-kdf.component.html", }) export class ChangeKdfComponent implements OnInit { - kdf = KdfType.PBKDF2_SHA256; kdfConfig: KdfConfig = DEFAULT_KDF_CONFIG; kdfType = KdfType; kdfOptions: any[] = []; @@ -31,8 +34,8 @@ export class ChangeKdfComponent implements OnInit { protected ARGON2_PARALLELISM = ARGON2_PARALLELISM; constructor( - private stateService: StateService, private dialogService: DialogService, + private kdfConfigService: KdfConfigService, ) { this.kdfOptions = [ { name: "PBKDF2 SHA-256", value: KdfType.PBKDF2_SHA256 }, @@ -41,19 +44,22 @@ export class ChangeKdfComponent implements OnInit { } async ngOnInit() { - this.kdf = await this.stateService.getKdfType(); - this.kdfConfig = await this.stateService.getKdfConfig(); + this.kdfConfig = await this.kdfConfigService.getKdfConfig(); + } + + isPBKDF2(t: KdfConfig): t is PBKDF2KdfConfig { + return t instanceof PBKDF2KdfConfig; + } + + isArgon2(t: KdfConfig): t is Argon2KdfConfig { + return t instanceof Argon2KdfConfig; } async onChangeKdf(newValue: KdfType) { if (newValue === KdfType.PBKDF2_SHA256) { - this.kdfConfig = new KdfConfig(PBKDF2_ITERATIONS.defaultValue); + this.kdfConfig = new PBKDF2KdfConfig(); } else if (newValue === KdfType.Argon2id) { - this.kdfConfig = new KdfConfig( - ARGON2_ITERATIONS.defaultValue, - ARGON2_MEMORY.defaultValue, - ARGON2_PARALLELISM.defaultValue, - ); + this.kdfConfig = new Argon2KdfConfig(); } else { throw new Error("Unknown KDF type."); } @@ -62,7 +68,6 @@ export class ChangeKdfComponent implements OnInit { async openConfirmationModal() { this.dialogService.open(ChangeKdfConfirmationComponent, { data: { - kdf: this.kdf, kdfConfig: this.kdfConfig, }, }); diff --git a/apps/web/src/app/auth/settings/two-factor-authenticator.component.html b/apps/web/src/app/auth/settings/two-factor-authenticator.component.html index 33bf4fb130..e17714cca7 100644 --- a/apps/web/src/app/auth/settings/two-factor-authenticator.component.html +++ b/apps/web/src/app/auth/settings/two-factor-authenticator.component.html @@ -15,13 +15,6 @@
- -
- - ×
- - × - - - -